Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: An entity copy was already assigned to a different entity

HiAll,

i try currently to understand, what is wrong in my coding and entity model I use the hibernate 4.2 to for CRUD operation with just Generic DAO pattern and annotated entities with cascading ALL and orphanRemoval= true. I have the DayPlan entity with OneToMany relationship to DayPlanElement weak entity. The DayPlanElement are saved into java.util.Set. Each DayPlanElement has a property "order".

The DayPlan has also OneToMany relationship to an entity Person. The entity Person saved into java.util.List.

The DayPlanElement has OneToMany relationship to DayPlanElementEntry weak entity. java.util.Set used for save. The Person entity also OneToMany relationship to DayPlanElementEntry weak entity. java.util.Set used for save. The DayPlan, DayPlanElement and Person entities have the ID, managed by my application, as String. The DayPlanElementEntry weak entity has a composite Id: DayPlanElementEntryId annotated with EmbeddedId, contains the parentPersonId and dayPlanElementId. It

In other words imagine, that exists a table, represents the day plan. The columns are the hours from 0 up to 24. The rows are the persons, that must proceed the operations from day plan. Each column would be DayPlanElement entity. Each row would be Person entity. And each cell would be DayPlanElementEntry entity.

If i just add to table new elements (also Persons) and remove its (also remove its from List and then call the DayPlanDAO.merge(dayPlan) - i hope on cascading and orphanRemoval) - i have no problem.

Only if i try to reorder the given Persons (just removing operations within java.util.List) and the call DayPlanDAO.merge(dayPlan) - the following excepion will be thrown:

Caused by: java.lang.IllegalStateException: 
Error occurred while storing entity 
[DayPlanElementEntry [getDayPlanMode()=NONE, getCompositeId()=DayPlanElementEntryId [parentPersonId=874c8eac-8796-478d-a4d5-dd011f7d6a4b, dayPlanElementId=ab683a25-633e-419e-89b6-4aef7829d4f6], hashCode=-2039940039]]. 

An entity copy 
[org.hw.domain.DayPlanElementEntry#DayPlanElementEntryId [parentPersonId=874c8eac-8796-478d-a4d5-dd011f7d6a4b, dayPlanElementId=ab683a25-633e-419e-89b6-4aef7829d4f6]] 

was already assigned to a different entity 

[org.hw.domain.DayPlanElementEntry#DayPlanElementEntryId [parentPersonId=874c8eac-8796-478d-a4d5-dd011f7d6a4b, dayPlanElementId=ab683a25-633e-419e-89b6-4aef7829d4f6]].

       at org.hibernate.event.internal.EventCache.put(EventCache.java:192)

       at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285)

       at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)

I debugeg the EventCache, seaching for problem solutions, just check implemented equals() and hashCode() method - without success:-(( Notice, i use for equals() method the Id. For instance the composite id of DayPlanElementEntry. That id is used by hashCode(). I just not understand the error message, thrice times will be output the same properties - the ids!

I found the test class for event cache, but now i don't understand the following use case test:

    @Test
public void testCopyAssociatedWith2ExistingEntities() {
session.getTransaction().begin();
Simple entity1 = new Simple( 1 );
session.persist( entity1 );
Simple copy1 = new Simple( 1 );
cache.put(entity1, copy1);
Simple entity2 = new Simple( 2 );
session.persist( entity2 );
Simple copy2 = new Simple( 2 );
cache.put( entity2, copy2 );
session.flush();

try {
cache.put( entity1, copy2 );
fail( "should have thrown IllegalStateException");
}
catch( IllegalStateException ex ) {
// expected
assertTrue( ex.getMessage().startsWith( "Error occurred while storing entity [org.hibernate.event.internal.EventCacheTest$Simple#1]." ) );
}
session.getTransaction().rollback();
}

....

    @Entity
private static class Simple {
@Id
private int value;

public Simple(int value) {
this.value = value;
}

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}
}

We have the Simple entity entity1 with Id=1, Then we persist it. Then we create the Simple entity copy1 and put into event cache it as value. As key the persisted entity*1* used. Then we create a Simple entity*2* with Id=2 , persist it, and then create the copy*2* entity with id 2 and put it as value into event cache. As key the persisted entity2 used. Why such situation is wrong and why is expected, that IllegalStateException must be thrown??

Thanks for your help!

like image 797
Kamen Jahr Avatar asked Jul 13 '13 21:07

Kamen Jahr


5 Answers

This can be resoloved by upgrading to hibernate 4.2.15 / 4.3.6 or above and add the following lines to your persistence.xml:

<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>

Refer https://hibernate.atlassian.net/browse/HHH-9106 for more details

like image 181
Suraj Menon Avatar answered Nov 11 '22 10:11

Suraj Menon


In jpa configuration file add below it will solve the issue.

In many to many relationship if the same entity are repeating while performing merger operation with already exists entities hibernate will not able to differentiate between them until we help him to get the difference.

properties.put("hibernate.event.merge.entity_copy_observer", "allow");
like image 34
Chaitanya Avatar answered Oct 18 '22 21:10

Chaitanya


I have the same problem with my code. Try this solution:

It is probably caused by two "cascade.all". when working with a DayPlan entity, it would have both list and list and both have 1:M to DayPlanElementEntry.

So two "cascade.all" might find DayPlanElementEntry have been assigned to Person when DayPlanElement try to access it, even it is the same DayPlanElementEntry.

I hope it helps.

Best, Chong

like image 44
Chong Yue Avatar answered Nov 11 '22 09:11

Chong Yue


For Hibernate version 4.3.4 and around, there is a fix out. Just add this artifact:

<dependency>
    <groupId>com.intersult</groupId>
    <artifactId>jpa-fix</artifactId>
    <version>1.1</version>
</dependency>

This fix replaces the MergeEventListener with such one, that handles this kind of merge.

like image 10
Tires Avatar answered Nov 11 '22 08:11

Tires


If this is in the context of a test, I suggest you follow your session.flush() with a session.clear(). This will effectively clear your session cache which seems to be at the core of the issue.

Potential reasons for this issue(I can think of):

  • The same entity copy is being added to the cache under different entity keys. Set a breakpoint under the put method found in EventCache.java to get more details.
  • A newly introduced bug in the version of hibernate that you are using.
like image 1
Newbie Avatar answered Nov 11 '22 10:11

Newbie