org.hibernate.HibernateException: reassociated object has dirty collection reference

Hibernate JIRA | Steve Ash | 5 years ago
tip
Your exception is missing from the Samebug knowledge base.
Here are the best solutions we found on the Internet.
Click on the to mark the helpful solution and get rewards for you help.
  1. 0

    We have a Parent class with @Id of type byte[] and a Child class also with @Id of type byte[]. There is a bidirectional @OneToMany relationship "List<Child> getChildren()" in Parent with Cascade.ALL and FetchType.EAGER. We load a parent (eagerly loading its children) and detach this instance from the session. We later want to re-attach the parent + children insteances by using the Lock API with LockMode.NONE. This fails with: {panel} org.hibernate.HibernateException: reassociated object has dirty collection reference at org.hibernate.event.def.OnLockVisitor.processCollection(OnLockVisitor.java:71) at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:122) at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:83) at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:77) at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:144) at org.hibernate.event.def.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:101) at org.hibernate.event.def.DefaultLockEventListener.onLock(DefaultLockEventListener.java:82) at org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:774) at org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:766) at org.hibernate.impl.SessionImpl.access$600(SessionImpl.java:156) at org.hibernate.impl.SessionImpl$LockRequestImpl.lock(SessionImpl.java:2369) at com.argodata.fser.data.BlockManTest.testSimpleUpdate(BlockManTest.java:160) {panel} The problem is that {{ProxyVisitor}}'s {{isOwnerUnchanged}} uses id.equals( snapshot.getKey() ) to validate the the PersistentCollections snapshot owner id value is "equal" to the current id. For primitve keys like long and int this works, but for byte[] keys it fails as its a reference equals operation, not a value equals. If we switch our id type to long then we can re-attach the parent and children with the lock API as expected. Workaround is simple of course, just don't use array types for @Ids or wrap them with something that implements equals properly. However, considering that I believe primary arrays as keys are handled properly in other places, so I would guess that this is just an inconistency and that it should work as expected in ProxyVisitor as well. I will attach a TestCase replicating the problem shortly.

    Hibernate JIRA | 5 years ago | Steve Ash
    org.hibernate.HibernateException: reassociated object has dirty collection reference
  2. 0

    We have a Parent class with @Id of type byte[] and a Child class also with @Id of type byte[]. There is a bidirectional @OneToMany relationship "List<Child> getChildren()" in Parent with Cascade.ALL and FetchType.EAGER. We load a parent (eagerly loading its children) and detach this instance from the session. We later want to re-attach the parent + children insteances by using the Lock API with LockMode.NONE. This fails with: {panel} org.hibernate.HibernateException: reassociated object has dirty collection reference at org.hibernate.event.def.OnLockVisitor.processCollection(OnLockVisitor.java:71) at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:122) at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:83) at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:77) at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:144) at org.hibernate.event.def.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:101) at org.hibernate.event.def.DefaultLockEventListener.onLock(DefaultLockEventListener.java:82) at org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:774) at org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:766) at org.hibernate.impl.SessionImpl.access$600(SessionImpl.java:156) at org.hibernate.impl.SessionImpl$LockRequestImpl.lock(SessionImpl.java:2369) at com.argodata.fser.data.BlockManTest.testSimpleUpdate(BlockManTest.java:160) {panel} The problem is that {{ProxyVisitor}}'s {{isOwnerUnchanged}} uses id.equals( snapshot.getKey() ) to validate the the PersistentCollections snapshot owner id value is "equal" to the current id. For primitve keys like long and int this works, but for byte[] keys it fails as its a reference equals operation, not a value equals. If we switch our id type to long then we can re-attach the parent and children with the lock API as expected. Workaround is simple of course, just don't use array types for @Ids or wrap them with something that implements equals properly. However, considering that I believe primary arrays as keys are handled properly in other places, so I would guess that this is just an inconistency and that it should work as expected in ProxyVisitor as well. I will attach a TestCase replicating the problem shortly.

    Hibernate JIRA | 5 years ago | Steve Ash
    org.hibernate.HibernateException: reassociated object has dirty collection reference

    Root Cause Analysis

    1. org.hibernate.HibernateException

      reassociated object has dirty collection reference

      at org.hibernate.event.def.OnLockVisitor.processCollection()
    2. Hibernate
      SessionImpl$LockRequestImpl.lock
      1. org.hibernate.event.def.OnLockVisitor.processCollection(OnLockVisitor.java:71)
      2. org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:122)
      3. org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:83)
      4. org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:77)
      5. org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:144)
      6. org.hibernate.event.def.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:101)
      7. org.hibernate.event.def.DefaultLockEventListener.onLock(DefaultLockEventListener.java:82)
      8. org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:774)
      9. org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:766)
      10. org.hibernate.impl.SessionImpl.access$600(SessionImpl.java:156)
      11. org.hibernate.impl.SessionImpl$LockRequestImpl.lock(SessionImpl.java:2369)
      11 frames
    3. com.argodata.fser
      BlockManTest.testSimpleUpdate
      1. com.argodata.fser.data.BlockManTest.testSimpleUpdate(BlockManTest.java:160)
      1 frame