I'd like to remove entities from my table and have it auto-removed any entities that are childs of it.
Example:
class User {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval=true)
#OnDelete(action = OnDeleteAction.CASCADE)
List<Address> addresses;
}
When I remove a User that has no address, everything works fine. Also removing an address without removing the user works.
But: If I try to remove a user that has still some addresses, I'm getting org.hsqldb.HsqlException:
integrity constraint violation: foreign key no action; FK_ADDRESS_USER_ID table: ADDRESS
What might be wrong here?
Or is this not supported and I have to explicitly remove all contained Address objects first before deleting a user?
I believe you have a problem with a foreign key constraint. Use a DB tool like Aqua Data Studio or similar (you can probably also do this in your IDE, in Eclipse - Data Source Explorer view), to show the create script for your ADDRESS table. It should contain something like this:
ALTER TABLE TESTSCHEMA.ADDRESS
ADD CONSTRAINT FK1ED033D4E91AAFD9
FOREIGN KEY(FK_ADDRESS_USER_ID)
REFERENCES TESTSCHEMA.USER(ID)
ON DELETE CASCADE
The point being the ON DELETE CASCADE part in your case. If this is missing or is different, that probably is what is causing the problem. If the table is auto-generated by Hibernate, this constraint should be valid, but keep in mind that there are differences between databases. It could be that the table was generated before the Hibernate's #OnDelete annotation was added, so now you are getting the "foreign key no action" integrity constraint violation.
Not related to the issue, but do note that orphanRemoval=true will try to remove the address from the database, when it is removed from the collection in the User entity.
Also, check this out for details on Hibernate’s support for database ON DELETE CASCADE constraint.
Related
I have a simple unidirectional ManyToOne relationship on an entity, which unfortunately is defined in a schema I cannot change.
It is defined as follows
#Entity
#Table(name="Profile")
...
public class Profile{
#ManyToOne
#JoinColumn(name="usr_id", nullable=false, updatable=false)
private User usr;
...
and all is well. The relationship is enforced with a foreign key in the db, hence the nullable = false and updatable = false. There is no mention of the profiles in user.
When I try to delete a Profile, hibernate also tries to delete the User entity, which is parent to other relationships and therefore fails. I have no CascadeType annotations anywhere.
My intent is to have a simple reference to the user using this profile in the usr field. This is a unidirectional relationship. The user entity should not be affected whenever I delete a profile.
This appers to be achievable when the usr field may be dereferenced before delete (I can see in the hibernate generated sql that hibernate attempts to set the field to null before deletion) - however that fails because of the foreign key.
Is what I'm trying to do achievable? If so, how?
(I'm using spring data on top of hibernate, if that is relevant.)
further Infos: I have tried optional=false, and it leads to the delete the parent entity behaviour. I have tried all fitting combinations of CascadeTypes, #OnDelete with NO_ACTION (still tries to delete the user) and defining a reverse but owned by user relationship - no success so far. On top of that, I tried the search function ;), which lead me to the conclusion that this is just my problem. If I missed an answered question, I'd appreciate a pointer in the right direction. Thanks.
Do you have some kind of other non-nullable association #ManyToOne or #OneToOne to the Profile entity? You can debug into the deletion process by setting a break point in e.g. the JDBC driver in e.g. Connection.prepareStatement and go down the stack frames to the cascading part to figure out why this cascading happens.
If all that doesn't help, please create a reproducing test case and submit an issue to the Hibernate issue tracker.
I use following HQL query to delete a specific object in my database.
delete from com.ranking.Footballclub where id = 1
The problem I encounter when I do this, it breaks a foreign key.
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The DELETE
statement conflicted with the REFERENCE constraint
"FK_VKLC3OLNFZIT2FCYMMKDO2ERZ4". The conflict occurred in database
"sports", table "dbo.FOOTBALL_PLAYER", column 'CLUB_ID'
A sport teams has a slave of players. I could first delete all players before I delete the Footballclub. But a Footballclub has more than just players. It has for example a list of employees, transfers,... Their foreign keys will break as well.
For this case I'm looking for something in HQL to delete all slave fields in 1 statement.
you can set the ON DELETE CASCADE in the data base explicitly, or mark the required Child entity with the annotation #org.hibernate.annotations.OnDelete.
It will automatically adds the on delete to schema during the schema generation. like -
#OneToMany(fetch = FetchType.EAGER, mappedBy = "YOUR_PARENT",
cascade = CascadeType.REMOVE)
#org.hibernate.annotations.OnDelete(
action = #org.hibernate.annotations.OnDeleteAction.CASCADE)
private List<YOUR_CHILD> CHILDS;
You can only use #OneToMany(cascade=CascadeType.REMOVE) annotation at your Entity and delete it through entity manager. There is no option to do it with hql. Or use constraint in your DDL (foreign key delete cascade);
I have a problem with Hibernate (Thanks to Thomas now the problem is more legible).
In Short:
How to configure a ManyToMany association with Hibernate when the relationship has an attribute and we need save, delete and update in cascade?
In Large:
Imagine the following DataBase:
User Profile
M______N
|
attribute
There are 3 tables here:
"User", "Profile" and "User_Profile".
Now imagine User_Profile has 1 attribute for the relation (and obviously the keys).
Ok, now this is translating to Hibernate by the following:
User:
// The relation is Many to Many, but considering that it has an attribute, this is OneToMany with the ManyMany RelationShip
#OneToMany(mappedBy="user", targetEntity=UserProfile.class)
#Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})
#LazyCollection(LazyCollectionOption.TRUE)
private Set<UserProfile> userProfile = new HashSet<UserProfile>();
UserProfile:
#Id
#ManyToOne(targetEntity=User.class,fetch=FetchType.LAZY)
#Cascade({CascadeType.LOCK})
#JoinColumns({ #JoinColumn(name="...", referencedColumnName="...") })
private User user;
#Id
#ManyToOne(targetEntity=Profile.class,fetch=FetchType.LAZY)
#Cascade({CascadeType.LOCK})
#JoinColumns({ #JoinColumn(name="...", referencedColumnName="...") })
private Profile profile;
So, I think the configuration is correct, and the save, independently if the User has Profile childrens save all of them. The problem is when I try to update the user:
getHibernateTemplate().getSessionFactory().getCurrentSession().clear();
getHibernateTemplate().saveOrUpdate( user );
getHibernateTemplate().getSessionFactory().getCurrentSession().flush();
Hibernate don´t delete the Profile relation if there is an empty set of Profile childrens. Only add the profiles (override the old)... That´s rare... What´s the problem?
Thank you in advance
All you actually do is remove the relation and thus theres no DELETE to cascade, that's why nothing gets deleted.
Try adding the Hibernate cascade type DELETE_ORPHAN (using the #Cascade annotation) to make Hibernate delete entities that are not referenced anymore.
Additionally, I'd not remove the Mini entities alone. If there's no relation, i.e. the set of Minis is empty, it normally makes no sense to keep the SuperMini entities that now represent an empty collection (in rare cases it might make sense, just want you to think about whether you need them or not).
Edit:
Note that with DELETE_ORPHAN you should reuse the set, otherwise all the relations might be deleted and reinserted.
Basically Hibernate would then see the set being changed and would issue a delete for the "old" set and a reinsert for the "new" set. This could be wanted but in case you only want an update, i.e. only delete the entities that are not in the set anymore, you should do the following:
clear the set
add the "new" set to the reused and now cleared set using addAll(...)
This should trigger the update (and deletion of orphans) only.
I have 2 very simple POJOs and i have just one to one mapping between them.
contact.java
comment.java -- it has foreign key column to the contact.java
the code i have written is below.
contact.java
#OneToOne(optional= false,cascade = CascadeType.ALL, mappedBy="contact", fetch=FetchType.LAZY)
#org.hibernate.annotations.LazyToOne(org.hibernate.annotations.LazyToOneOption.NO_PROXY)
private Comment mComment;
comment.java
#OneToOne(fetch = FetchType.LAZY,cascade=CascadeType.ALL )
#JoinColumn(name="EW_CNTC_ID")
private Contact contact;
i am setting comment into contact pojo and finally i am saving contact.java
if i keep #OneToOne(optional= false, i am getting dataintegrityexception, constraintvoilationexception
if i changed #OneToOne(optional= true, then it is working.
i think that if optional is false, it is trying to insert contact, it find comment it is trying to insert comment, but it has reference to contact it has to set the foreign key without inserting contact it cannot keep foreign key ..
if optional true the contact can be inserted without comment and PK generated for contact and tat is set in the foreign key column of the contact.--- anyway this issue is solved.
one more thing i am loading contacts i need to lazy load the comments, it is no where working can some one help on this, i strictly need lazy loading of comment because of performance problm.
Thanks in advance.
We have this issue in hibernate 3. Hibernate 4 fixed this issue.
If you want to load only contacts not comments then try like this(Imply change it to manytoone relation).
#ManyToOne(fetch=FetchType.LAZY)
private Comment mComment;
I have the following scenario:
I have a system full of users. There is a desire to run contests for users who log into the site over a week or so. Therefore I needed to create a new Contest object which would contain both the entries and the winners.
I created something like this:
private Set<User>;
#OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
#JoinTable(name="contest_entries",
joinColumns = {#JoinColumn(name = "contest_fk", referencedColumnName="contest_id")},
inverseJoinColumns = {#JoinColumn(name = "user_fk", referencedColumnName="id")})
public Set<User> getEntries() {
return entries;
}
The idea being that a Contest can have multiple entries. Seems simple. It generates the following:
create table contest (contest_id numeric(19,0) identity not null, primary key (contest_id));
create table contest_entries (contest_fk numeric(19,0) not null, user_fk numeric(19,0) not null, primary key (contest_fk, user_fk));
alter table contest_entries add constraint FK7FBD0C65C4F120C2 foreign key (contest_fk) references contest;
alter table contest_entries add constraint FK7FBD0C656ABC75E3 foreign key (user_fk) references user_profile;
However, once a contest is over, the desire is to run another contest. When I attempt to create a new contest and have one of users who had entered previously enter again, I get a unique key constraint. Looking at the table DDL, it makes sense that it does.
So, in essence, I can't run two contests at the same time. I would also lose history of people entering the contests. That's not going to work. I need to be able to run two contests at once with the same users in different contests.
I'm new to JPA, so I have to believe I'm missing something obvious. The system already has a user table and it's populated full of users. There is a desire not to change that table structure. Any ideas on how to solve this? If it matters, the persistence implementation is Hibernate.
You actualy have a many-to-many relationship. So you should use the #ManyToMany annotation.