views:

635

answers:

3

Hello everybody

Here is my data model (simplified)

public class AddressBook {
 private List<Group> groups = new ArrayList<Group>();
 private List<People> peoples = new ArrayList<People>();

 @OneToMany(mappedBy = "addressbook", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
 @OnDelete(action = OnDeleteAction.CASCADE)
 @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
 public List<Group> getGroups() {
  return groups;
 }

 @OneToMany(mappedBy = "addressbook", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
 @OnDelete(action = OnDeleteAction.CASCADE)
 @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
 public List<People> getPeoples() {
  return peoples;
 }
}


public class Group {
 private AddressBook addressBook;


 @ManyToOne(fetch = FetchType.LAZY, optional = false)
 public void setAddressBook(AddressBook addressBook) {
  this.addressBook = addressBook;
 }
}

public class People {
 private AddressBook addressBook;
 private Group group;

 @ManyToOne(fetch = FetchType.LAZY, optional = false)
 public AddressBook getAddressBook() {
  return addressBook;
 }
 public Group getGroup() {
  return group;
 }
}

I want to delete a full group from my addressbook, and all the people belonging to this group. So I do code somthing like:

adressBook.getPeople().removeAll(peopleBelongingToGroupA);
adressBook.getGroups().remove(groupA);

But when my transaction is commited, Hibernate does first:

delete from groups where groupName='groupA';

instead of deleting the people first. That causes my FOREIGN_KEY constraint between people and group to be violated...

Is there a way to tell hibernate to delete the people first, then the groups? Is there a flaw in my model?

Thank you for your help!

+1  A: 

there are 2 options

1) call flush before the second delete

2) add an 'cascade' to your mappings: i.e. cascade="delete". A delete of the group will delete also delete members of the group.

Salandur
How can I add a cascacde delete between Group and People ?
Laurent K
+1  A: 

Have you tried putting setting the cascade on each @ManyToOne. You've only specified, in many ways, cascade deletion on the AddressBook. This property is for each association I believe.

The EJB3.0 specification is well worth having to hand when writing these beans. See http://jcp.org/en/jsr/detail?id=220

Update: Reading your datamodel again, there may be a missing annotation on people here that would explain the behaviour. Do you have cascade set on the link with people->group? This would explain why the first statement would first start by trying to delete the group. Presumably you would want an annotation for groups on people that does not cascade?

andygavin
A: 

You can either do it as two transactions or use the cascade=delete as someone mentioned. Actually, you probably want delete orphans, which does a cascading delete, but only deletes the Person if they're completely orphaned. This does 2 nice things:

1) All you do is delete the group and it automatically deletes the children (assuming your mappings are setup correctly). 2) If a Person can belong to more than one group, it will only delete that child Person object if it's orphaned, meaning no group references it.

That 2nd part is a big deal if a child object (Person in this case) can have multiple parents and thus the child shouldn't be deleted unless every parent relationship is deleted.

Chris Kessel