Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring JPA Many to Many: remove entity, remove entry in join table, BUT NOT REMOVE the other side

I have this use case:

  • I have Users.
  • I have Groups.
  • There is a N:N relation between Users and Groups.
  • I can not delete Users.
  • If I delete a Group, Users in that Group should not be deleted.

Users side:

@ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(
                    name = "USERS_GROUPS",
                    joinColumns = @JoinColumn(name = "USER_ID", referencedColumnName = "ID") ,
                    inverseJoinColumns = @JoinColumn(name = "GROUP_ID", referencedColumnName = "ID") )
    private List<GroupJPA> groups;

Group side:

@ManyToMany(mappedBy = "groups", cascade = CascadeType.ALL)
private List<UserJPA> returnsList;

If I delete a Group from User's group list, the group gets deleted from User's list, it gets deleted from the join table, and it doesn't get deleted from the Group table. This is the desire behavior.

But, if I delete an entire Group, what happens is, all the references in the join table get deleted, BUT ALSO the Users get deleted as well!! This can not happen.

I'm using 4.3.5.Final and Spring 4.3.0.RELEASE.

like image 483
Perimosh Avatar asked Jul 11 '16 02:07

Perimosh


People also ask

What is the solution to remove a many-to-many relationship?

To avoid this problem, you can break the many-to-many relationship into two one-to-many relationships by using a third table, called a join table. Each record in a join table includes a match field that contains the value of the primary keys of the two tables it joins.

How do I delete multiple records in JPA?

First of all you need to create a jpa query method that brings all records belong to id. After that you can do deleteAll() operation on List.

How do I delete an entity in JPA?

To delete a record from database, EntityManager interface provides remove() method. The remove() method uses primary key to delete the particular record.


1 Answers

You need to remove the cascade = CascadeType.ALL from the

@ManyToMany(mappedBy = "groups", cascade = CascadeType.ALL)
private List<UserJPA> returnsList;

The cascading is propagating all operations to the relationship elements. Which means when you delete merge ,persist whatever... These operations are also executed on the UserJPA entities.

Once you remove the group you need to be aware of who is the owner of the preationship. In your case the owner of the relationship is the UserJPA which means that all updates should happen through the owner.

Once the Cascading is removed you need to implement a method on the UserSide which looks like this:

removeFromGroup(Group group) {
    user.getGroups().remove(group);
    groups.removeUser(this);
}

This is in order to ensure that the collections are in sync.

like image 186
Alexander Petrov Avatar answered Dec 02 '22 17:12

Alexander Petrov