How to remove orphan children when parent is saved

43 Views Asked by At

Long story short situation is the following

I have a Document, the document has many fields of different types. One of this fields is of Authorization type which accepts a list of authorizer actions. I need, when I update the document and change list of authorizer actions, the old authorizer actions are successfully removed from DB.

class Document {
    @OneToMany(mappedBy = "_field", fetch = FetchType.LAZY, cascade = {
            CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE, CascadeType.DETACH})
    private final SortedSet<Field<?>> _fields = new TreeSet<>();
}

class Field<T> {
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "document_id", nullable = false)
    private Document _document;

    @OneToMany(mappedBy = "_documentField", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
           orphanRemoval=true )
    private SortedSet<AuthorizerAction> _authorizers;
}

class AuthorizerAction {
   @ManyToOne(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.REFRESH } )
   @JoinColumn(name = "field_id", nullable = false)
   private Field<FiledAuthType> _documentField;

   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "user_id")
   private User _authorizer;
}

enter image description here

But, whatever changes I apply, I am getting different issues, or it's just not working as expected, and can not find an elegant solution without manually removing the authorizers from DB.

Suppose I'm getting a Document object from DB with all its dependences. I change it's list of AuthorizerActions and when I save the document object , I'm using

_documentDao.save(document);

After save, the delete orphans is triggered, but fails with error that object is already detached.

  • In some cases, the orphans are succesfuly removed, mostly when the object AuthorizerActions is updated.
  • In other cases no error is thrown but the orphans are not removed from DB, and
  • In some cases that error is thrown.
Caused by: java.lang.IllegalArgumentException: Removing a detached instance com.test.document.domain.AuthorizerAction#6
at org.hibernate.jpa.event.internal.core.JpaDeleteEventListener.performDetachedEntityDeletionCheck(JpaDeleteEventListener.java:52)
at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:89)
at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:1013)
at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:943)
at org.hibernate.engine.internal.Cascade.deleteOrphans(Cascade.java:553)
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:526)
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:423)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:386)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:193)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:126)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:445)
at org.hibernate.event.internal.DefaultPersistEventListener.justCascade(DefaultPersistEventListener.java:172)

Could you please help me understand where I am wrong?

0

There are 0 best solutions below