Hibernate annotation: one-To-one onDelete action cannot set to CASCADE - database

I would like to create two table USER and USERDETAIL to fulfill:
USERDETAIL have reference to USER table.
Operation on USER table do not need to aware of USERDEAIL table existence.
This should be one-to-one non bidirectional relationship.
The entity classes:
#Entity
#Table(name="USER")
public class User implements Serializable{
#Id
#Column(name="ID")
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
//...
}
#Entity
#Table(name="USERDETAIL")
public class UserDetail implements Serializable{
#Id
#Column(name="ID")
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign",
parameters = #Parameter(name = "property", value = "user"))
private String id;
#OneToOne(optional= false , targetEntity=User.class, cascade= CascadeType.ALL)
#OnDelete(action = OnDeleteAction.CASCADE)
//#JoinColumn(name="foreign_id",referencedColumnName="ID")
#PrimaryKeyJoinColumn
private User user;
//...
}
This create two table correctly and the USERDETAIL have foreign key constraint that its primary key is refernece by USER's id. However, the on Delete action is Restrict but not Cascade. I cannot delete a row of USER because of this.
I am using MySQL Sever 5.1. It does not seem like it does not support on delete action is cascade. Because I can manually delete the constraint and add a new constraint that set to on delete is cascade and work as I expected.

Your code should be:
#Entity
#Table(name="USER")
public class User implements Serializable{
#Id
#Column(name="ID")
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
//...
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="userdetail_id")
public UserDetail getUserDetail() {
...
}
}
#Entity
#Table(name="USERDETAIL")
public class UserDetail implements Serializable{
#Id
#Column(name="ID")
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign",
parameters = #Parameter(name = "property", value = "user"))
private String id;
#OneToOne(optional= false , targetEntity=User.class, mappedBy = "userDetail")
#PrimaryKeyJoinColumn
private User user;
//...
}
Basically, I suggest to make it bidirectionaly, with User class is the owner (by using mappedBy in UserDetail class). That way, when you delete a user, user detail will be deleted.

Finally, I have solved the problem.
First of all, I have follow http://www.mkyong.com/hibernate/hibernate-one-to-one-relationship-example-annotation/ to create oneToOne mapping entities.
However, when I start the Tomcat, it always throw NullPointerException on mapping. Therefore, I come up with my question entities and seem to work fine except the deletion.
I finally realize it is just a bug that hibernate-anoatation cause. I then use 3.4.0.ga version and follow the link again. By replace #GeneratedValue(strategy = IDENTITY) (I don't know why using this, hibernate cannot create table) to
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
it work as I expected.
Although there is no foreign-key constrain on the table, deleting owner (USER) table really can also delete the child (USERDETAIL) table correctly with hibernate handle.
I also do not need to worry about update owner table with no child field on it. The mappedBy side actually has no physical mapping defined as Khue Vu said. Hibernate is smart enough not to delete the relation.

Related

Using aliases in stored procedures with JPA entity

I have a Workers table with column name: "WorkerID"
so I have created entity with #Column(name = "WorkerID").
Whenever I try to use stored procedure that selects WorkerID as ID, it doesn't work. It says The column name WorkerID is not valid.
Is there any annotation I can use to make the both parameters WorkerID and ID not to be mandatory? (so I can use this stored procedure and a simple select on workers table)
The exception given upon executing the query:
com.microsoft.sqlserver.jdbc.SQLServerException: The column name worker_id is not valid.
Failed query:
SELECT Worker_ID AS [ID] From Workers
Working query:
SELECT Worker_ID From Workers
The entity:
#PropertySource("classpath:application.properties")
#Entity
#Table(name = "Workers")
#Data
#NoArgsConstructor
#RequiredArgsConstructor
public class Worker {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Worker_ID")
protected long Worker_ID;
#Column(name = "Email")
private String Email;
#Column(name = "Username")
private String Username;
}
I want to be able to run both queries with the same entity. Is it feasible?
Thanks!

Google App Engine Objectify 5.1.21 - Many-to-many relationship queries

I'm new on Objectify coding and I need your help to solve a problem with Many-to-many relationship query.
I have 2 entities named User and Installation:
#Entity
public class User {
#Id private String login;
private String password;
#Index private String name;
#Index private String firstName;
#Index private byte right;
}
#Entity
public class Installation {
#Id private long id;
#Index private long clientId;
#Index private String name;
private String address1;
private String address2;
#Index private String postCode;
private String city;
#Index private String countryCode;
#Index private int status;
}
A user can access to several installation and an installation can have several users : many-to-many relationship. I want to map these entities but I don't want to load systematically installations when I load users. So, I created an entity for mapping Users and Installations :
#Entity
public class InstallUser {
#Id private Long id;
#Index Key<User> userKey;
#Index Key<Installation> instalKey;
public void setLink(User user, Installation instal){
//initialize
this.userKey = Key.create(User.class, user.getLogin());
this.instalKey = Key.create(Installation.class, instal.getId());
}
}
Could you help me for writing the queries to :
load all installations of a user identified by his login (#id) ;
load all users who have access to an installation identified by its id (#id) ;
load all installations of a user identified by his login (#id) and filtered by his right (right=2 for example).
Thank you in advance for your help.
While the datastore doesn't do joins for you, you can still do joins - you're the query planner. So do what an RDBMS would do. For example, to perform #1 ("load all installations of a user identified by his login") you would:
Make a Key<User> for that user
Find all InstallUsers associated with that user
Use all the relevant Key<Installation>s to batch load the installatons.
You can be slightly more clever by using Ref<?>s instead of Key<?>s in the InstallUser and using the #Load annotation to automatically fetch the Installation.
There are quite a few other ways of structuring this data as well. Depending on the arity of the relationships, you might use a list property in either User or Installation instead of a separate relationship entity. But you're on the right path.

how to mapping hibernate entity to db view

Could you help me how can I mapping to any entity to db view?
Scenario is here, We create a view on db with native sql we have to do like this and we want to mapping this view to ours entity.
How can we do that? We try to create an entity with same columns on view but it doesn't work?
Hibernate-specific #Immutable annotation which I use in the following code snippet.
View can be mapped as like below....
#Entity
#Immutable
public class <NAME>View {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#Version
#Column(name = "version")
private int version;
The #Immutable annotation tells Hibernate to ignore all changes on this entity, but you can use it to retrieve data from the database.
List<View> views = em.createQuery("SELECT v FROM View v", View.class).getResultList();

spring data insert if not exists entity with field

Can anyone recommend a way to perform inserts in a database table via spring data jpa (in a clustered environment) only when the entry doesn't already exist in the database?
As an example situation, take a database with message and email_address tables. When a new message addressed to 'user#so.com' is added to the message table, a check will be done in the email_address table whether the email 'user#so.com' exists in the email_address and if it doesn't, it gets added to the database. Afterwards the email address entity field is set on the message entity and subsequently the message entity is saved.
#Entity
public class Message {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private EmailAddress emailAddress;
private String content;
}
#Entity
public class EmailAddress {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
// a unique constraint exists on this field on the database
private String email;
}
What should there be done with the spring data jpa EmailAddressRepository to avoid database exceptions that can occur when concurrently trying to insert entities with the same email address?
You could run a check inside a #PrePersist annotated method in your entity. Other than that, I don't think JPA or spring-data provide something out of the box for that.

How to generate a hibernate ID with auto generate with a starting value

Hi I have written code like this
#Id
#Column(nullable=false)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getUserID() {
return UserID;
}
But I manually setting it from DAO like "e.setUserID(01);" to insert.Otherwise row not inserting Is there any process to get value to id and retrieve what value generated automatically. Im thinking i will get some help
Use the IDENTITY generation type instead of auto. Use a Long for id. I also recommend changing the name from UserID to userId. Do not forget the #Entity for the class name.
#Entity
public class MyClass{
private Long userId;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
public Long getUserID(){
return userId;
}
//.. rest of class
}
Be very careful with the naming conventions and make sure your field names and types match the field names and types from the database.
Use
#GenericGenerator(name="generator", strategy="increment")
#GeneratedValue(generator="generator")

Resources