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

Hibernate JIRA | Steve Ash | 5 years ago
tip
Click on the to mark the solution that helps you, Samebug will learn from it.
As a community member, you’ll be rewarded 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