Kadzhaev Marat
Kadzhaev Marat

Reputation: 1317

Hibernate cascade deleting doesn't work

I have 3 entity: 'Person', 'Document', 'PersonDocument' which related as following:

class Person {
    @Cascade(CascadeType.ALL)
    @OneToMany(mappedBy = "person", orphanRemoval = true, fetch = FetchType.LAZY)
    Set<PersonDocument> personDocuments;
}

class Document {
    @OneToMany(mappedBy = "document")
    Set<PersonDocument> personDocuments;
}

@IdClass(PersonDocumentPK.class)
public class PersonDocument {
    @Id
    private Person person;
    @Id
    private Document document;

    @ManyToOne(fetch = FetchType.LAZY)
    private Provider provider;
}

public class PersonDocumentPK implements Serializable {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "person_guid")
    private Person person;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "documents_guid")
    private Document document;
}

In my code I am trying to delete some records from Person#personDocuments and add new records. I am doing it like:

Iterator it = person.getPersonDocuments().iterator();
PersonDocument pd = it.next();
if (some logic) it.remove();
...
person.getPersonDocuments().addAll(new set of values);    

In result removed personDocuments have disappeard, but related documents remained on database. Why is so?

Upvotes: 1

Views: 2132

Answers (2)

Roque Santos
Roque Santos

Reputation: 245

Cascade operations doesn't work like that.

When you use the @Cascade annotation, operations made in the parent will cascade to child assossiations depending on the cascade type.

As your class is annotated with CascadeType.ALL, all operations made in the parent class will cascade to the childs.

So, for the remove to work, you would need to call entityManager.remove(person), and then the persistence provider would call the remove in the childs too.

That being said, change your code to somethng like that:

Iterator it = person.getPersonDocuments().iterator();
PersonDocument pd = it.next();
if (some logic)  {
   it.remove();
   em.remove(pd); // No problem to call in the loop because it will call the database only on commit or flush
}
...

person.getPersonDocuments().addAll(new set of values);   

Upvotes: 1

Azzabi Haythem
Azzabi Haythem

Reputation: 2423

try CascadeType.DELETE instead of CascadeType.ALL

@Cascade({CascadeType.SAVE_UPDATE, CascadeType.DELETE})

Upvotes: 0

Related Questions