A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance

Introduction

Hibernate is an ORM provider. ORM is an object-relationship mapper. Hibernate Persistent class takes the values from the Java class attributes and persists them in the database.

Problem Statement

So recently I came across an interesting issue while working on hibernate persistence. I had an object certificate which had a child collection object certificateProperties. While updating an object that refers to certificate, it keeps throwing an error as below:

A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.betterjavacode.model.Certificate.certificateProperties; nested exception is org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.infor.security.sts.config.model.Certificate.certificateProperties
 at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:333)
 at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
 at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:765)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:734)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
 at com.sun.proxy.$Proxy213.save(Unknown Source)

It was surprising to see this error randomly popping up. I was wondering if I missed orphanRemoval tag on my object certificate for certificateProperties, but it was there. So definitely it was not the issue. Also to remember, I was using cascade = CascadeType.ALL for cascading persistence of certificate.

Solution

Now if you notice, hibernate gives enough information about the error to notice what is happening. Hibernate is complaining that it is not able to track the change for the child collection object certificateProperties while it is getting set in the parent object certificate. Hibernate requires that parent object owns a child collection object completely.

To fix this issue, the solution was simple

Old Code

    public void setCertificateProperties(Set<CertificateProperty> certificateProperties)
    {
        this.certificateProperties = certificateProperties; 
    }

Solution Code
    private Set<CertificateProperty> certificateProperties = new HashSet<>();

    public void setCertificateProperties(Set<CertificateProperty> certificateProperties)
    {
        this.certificateProperties.addAll(certificateProperties);
    }

 

Conclusion

We showed how hibernate can handle the persistence in the cascade operation. If you enjoyed this post, please subscribe to my blog here.