Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 313539

Summary: [Hibernate] NonUniqueObjectException when saving a model with cyclical references
Product: [Modeling] EMF Reporter: Austin Teng <austin.teng>
Component: cdo.coreAssignee: Martin Taal <mtaal>
Status: CLOSED FIXED QA Contact: Eike Stepper <stepper>
Severity: critical    
Priority: P3 CC: austin.teng, stepper
Version: 3.0   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Stack trace
none
Test case (includes EMF model)
none
Proposed patch none

Description Austin Teng CLA 2010-05-19 10:51:50 EDT
Build Identifier: 20100218-1602

The attached test code (HibernateStoreBidirectionalTest.zip) produces an exception (NonUniqueObjectException.txt) when attempting to save the model to a CDO Server configured to use a Hibernate Store.  The code is built against a January 18th nightly, fairly close to the head of the "Root_branching" branch.

The problem seems to be with references that introduce cycles in the object graph.  If multiple objects in the committed change sub-graph reference a common object, Hibernate will produce a NonUniqueObjectException while attempting to lazily initialize the second copy of the shared object during a saveOrUpdate operation.

The problem can be avoided by taking the following actions:

1. Make sure the following property is *NOT* set:

<property name="teneo.mapping.cascade_policy_on_non_containment" value="PERSIST,MERGE"/>

This will avoid calling persist or merge on related objects that should be unaffected by changes to the initial object.  For example, if A references B, and A is changed, B should remain unaffected.

2. Using the merge operation instead of saveOrUpdate in the write operation of the HibernateStoreAccessor (HibernateStoreBidirectionalFix.patch).  This appears to work, however, I'm unsure if there are more subtle consequences to the approach I've taken.

Reproducible: Always

Steps to Reproduce:
1. Launch a CDO Server locally that is configured with the following options:
   - Hibernate Store
   - Teneo dynamic mapping provider
   - HSQLDB (any database works, but this is easiest)
2. Disable the cascade policy property (see description) in the CDO Server config
   - Leaving it enabled will trigger a different failure point caused by the bidirectional reference between Student and School
   - Disabling it triggers a failure caused by the reflexive "sibling" relationship
3. Run the unit test included in the attachments
Comment 1 Austin Teng CLA 2010-05-19 10:53:18 EDT
Created attachment 169128 [details]
Stack trace
Comment 2 Austin Teng CLA 2010-05-19 10:53:57 EDT
Created attachment 169129 [details]
Test case (includes EMF model)
Comment 3 Eike Stepper CLA 2010-05-19 10:54:59 EDT
Martin, this seems to be Hibernate-related?
Comment 4 Austin Teng CLA 2010-05-19 10:55:02 EDT
Created attachment 169131 [details]
Proposed patch
Comment 5 Martin Taal CLA 2010-05-31 09:41:22 EDT
A patch to fix this issue has been attached to this bugzilla:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=315067
Comment 6 Martin Taal CLA 2010-05-31 12:43:22 EDT
A patch which solves this issue has been committed. Will be in the next build of CDO.
Comment 7 Eike Stepper CLA 2010-06-29 04:36:33 EDT
Available in 3.0 GA:
http://download.eclipse.org/modeling/emf/cdo/updates/3.0-releases/