Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Data Jpa - ManyToMany - delete entities of the join table

I have these two classes :

public class ClassA extends [...] implements [...] {
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = JOIN_TABLE_NAME,
            joinColumns = @JoinColumn(name = COLUMN_REF_A, referencedColumnName = COLUMN_ID_A),
            inverseJoinColumns = @JoinColumn(name = COLUMN_REF_B, referencedColumnName = COLUMN_ID_B))
    private List<ClassB> fieldClassB;   
}

public class ClassB extends [...] implements [...] {
    @ManyToMany(fetch = FetchType.LAZY, mappedBy = "fieldClassB", cascade = CascadeType.ALL)
    private List<ClassA> fieldClassA;

}

When I delete ClassB (via the spring data jpa repository), Hibernate also deletes instances of ClassA, whereas I just want the rows in the JOIN_TABLE_NAME table to be deleted (the other issue is that, due to the cascade mode, deleting the ClassA entities also delete other ClassB referenced by these ClassA).

Is there any way to handle this without having to create the join entity and to replace the @ManyToMany annotations by @OneToMany referencing the new join entity ?

like image 752
Thoomas Avatar asked Jan 24 '18 09:01

Thoomas


People also ask

How do I delete an entity in JPA?

In JPA, to delete an entity, the entity itself must be managed, meaning that it is present in the persistence context. This means that the calling application should have already loaded or accessed the entity and is now issuing a command to remove it.

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.

Which method is used to delete data in JPA?

We can use the JPA method deleteById() for deleting the record of the particular primary key.


1 Answers

Cascade Remove in a manyToMany it's not only applied to the link table, but to the other side of the association as well.

So Cascade.ALL which inherit remove too is almost always a bad thing to have on a manyToMany as it ends up deleting things not only from association table.

What you want is to have add and remove method in your entities to do the work and keep both list synchronized:

public class ClassA extends [...] implements [...] {
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinTable(name = JOIN_TABLE_NAME,
            joinColumns = @JoinColumn(name = COLUMN_REF_A, referencedColumnName = COLUMN_ID_A),
            inverseJoinColumns = @JoinColumn(name = COLUMN_REF_B, referencedColumnName = COLUMN_ID_B))
    private List<ClassB> fieldClassB; 

    public void addClassB(ClassB b) {
        fieldClassB.add(b);
        b.fieldClassA().add(this);
    }

    public void removeClassB(ClassB b) {
        fieldClassB.remove(b);
        b.fieldClassA().remove(this);
    }  
}
like image 85
Zeromus Avatar answered Oct 14 '22 22:10

Zeromus