JPA (with Play!) bidirectional Many-to-Many - how to remove from both sides of the relationship?
I have the following mapping in my Play! app using JPA:
@Entity
public class Contact extends Model {
public String name;
@ManyToMany(mappedBy = "contacts", fetch = FetchType.EAGER)
public Set<Category> categories = new HashSet<Category>();
public void addCategory(Category c) {
this.categories.add(c);
if (!c.contacts.contains(this)) {
c.contacts.add(this);
}
}
@PreRemove
public void preRemove() {
for (Category c : this.categories) {
c.contacts.remove(this);
}
this.categories = null;
}
}
@Entity
public class Category extends Model {
public String name;
@ManyToMany
public Set<Contact> contacts = new HashSet<Contact>();
public void addContact(Contact c) {
this.contacts.add(c);
if (!c.categories.contains(this)) {
c.categories.add(this);
}
}
@PreRemove
protected void preRemove() {
for (Contact c : this.contacts) {
c.categories.remove(this);
}
this.contacts = null;
}
}
Deleting Category works fine, the relationship is updated correctly. If I delete a Contact however, I'm getting a constraint violation:
Caused by: org.h2.jdbc.JdbcBatchUpdateException: Referential integrity constraint violation: "FK34B085DF487AF903:
PUBLIC.CATEGORY_CONTACT FOREIGN KEY(CONTACTS_ID) REFERENCES PUBLIC.CONTACT(开发者_如何学PythonID)"; SQL statement:
delete from Contact where id=? [23003-149]
How can I ensure that deleting a Contact will not delete the Category but will only remove the relationship?
EDIT: Duh! The issue was I also had a User object which had references to both Contact and Category. I missed clearing that relationship. The following is the change to preRemove() method in Contact class:
@PreRemove
public void preRemove() {
for (Category c : this.categories) {
c.contacts.remove(this);
}
this.user.contacts.remove(this);
for (Category c : this.user.categories) {
c.contacts.remove(this);
}
//It's important to save the user
this.user.save();
}
An other solution is to manually remove elements from the list and save it, before deleting the main entity :
while( !contact.categories.isEmpty() ) {
contact.categories.remove(0);
}
contact.save();
contact.delete();
精彩评论