How to remove entity with ManyToMany relationship in JPA (and corresponding join table rows)?

rdk picture rdk · Jul 4, 2009 · Viewed 103.3k times · Source

Let's say I have two entities: Group and User. Every user can be member of many groups and every group can have many users.

@Entity
public class User {
    @ManyToMany
    Set<Group> groups;
    //...
}

@Entity
public class Group {
    @ManyToMany(mappedBy="groups")
    Set<User> users;
    //...
}

Now I want to remove a group (let's say it has many members).

Problem is that when I call EntityManager.remove() on some Group, JPA provider (in my case Hibernate) does not remove rows from join table and delete operation fails due to foreign key constrains. Calling remove() on User works fine (I guess this has something to do with owning side of relationship).

So how can I remove a group in this case?

Only way I could come up with is to load all users in the group, then for every user remove current group from his groups and update user. But it seems ridiculous to me to call update() on every user from the group just to be able to delete this group.

Answer

Grzegorz Oledzki picture Grzegorz Oledzki · Jul 6, 2009
  • The ownership of the relation is determined by where you place the 'mappedBy' attribute to the annotation. The entity you put 'mappedBy' is the one which is NOT the owner. There's no chance for both sides to be owners. If you don't have a 'delete user' use-case you could simply move the ownership to the Group entity, as currently the User is the owner.
  • On the other hand, you haven't been asking about it, but one thing worth to know. The groups and users are not combined with each other. I mean, after deleting User1 instance from Group1.users, the User1.groups collections is not changed automatically (which is quite surprising for me),
  • All in all, I would suggest you decide who is the owner. Let say the User is the owner. Then when deleting a user the relation user-group will be updated automatically. But when deleting a group you have to take care of deleting the relation yourself like this:

entityManager.remove(group)
for (User user : group.users) {
     user.groups.remove(group);
}
...
// then merge() and flush()