休眠:实体副本已分配给不同的实体

Kam*_*ahr 9 merge hibernate

大家好,

我目前正在尝试理解,我的编码和实体模型有什么问题我使用hibernate 4.2来进行CRUD操作,只使用Generic DAO模式和带有级联ALL和orphanRemoval = true的带注释实体.我有DayPlan实体与DayToMany关系到DayPlanElement弱实体.该 DayPlanElement被保存到java.util.Set中.每个DayPlanElement都有一个属性"order".

DayPlan也有一个实体一对多关系的人.实体Person保存到java.util中.清单.

DayPlanElement具有一对多关系DayPlanElementEntry弱实体.java.util.Set用于保存.该人士实体也一对多关系DayPlanElementEntry弱实体.java.util.Set用于保存.该DayPlan,DayPlanElement实体有ID,通过我的应用程序管理,为String.该DayPlanElementEntry弱实体具有复合编号:DayPlanElementEntryId与EmbeddedId注释,包含parentPersonId和dayPlanElementId.它

换句话说,想象一下,存在一个表,代表日计划.列是从0到24的小时数.行是人员,必须从日计划开始操作.每列都是DayPlanElement实体.每一行都是Person实体.每个单元格都是DayPlanElementEntry实体.

如果我只是添加到表新元素(也是人)并删除它(也从列表中删除它,然后调用DayPlanDAO.merge(dayPlan) - 我希望在级联和orphanRemoval) - 我没有问题.

只有当我尝试重新排序给定的人(只是删除java.util.List中的操作)和调用DayPlanDAO.merge(dayPlan)时,才会抛出以下异常:

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)
Run Code Online (Sandbox Code Playgroud)

我去了解EventCache,找到问题解决方案,只检查实现的equals()和hashCode()方法 - 没有成功: - (注意,我使用equals()方法的Id.例如DayPlanElementEntry的复合id.那个id是hashCode()使用.我只是不明白错误信息,三次输出相同的属性 - ids!

我找到了事件缓存的测试类,但现在我不理解以下用例测试:

    @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();
}
Run Code Online (Sandbox Code Playgroud)

....

    @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;
}
}
Run Code Online (Sandbox Code Playgroud)

我们有Id = 1的简单实体entity1 ,然后我们坚持它.然后我们创建Simple实体copy1并将其作为值放入事件缓存中.使用持久化实体*1*作为关键.然后我们创建一个Id = 2的Simple实体*2*,保持它,然后创建id为2 的copy*2*实体,并将其作为值放入事件缓存中.作为持久化实体2使用的关键.为什么这种情况是错误的,为什么会出现这种情况,必须抛出IllegalStateException?

谢谢你的帮助!

Tir*_*res 10

对于Hibernate版本4.3.4及其周围,有一个修复.只需添加此工件:

<dependency>
    <groupId>com.intersult</groupId>
    <artifactId>jpa-fix</artifactId>
    <version>1.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

此修补程序将MergeEventListener替换为处理此类合并的MergeEventListener.


Cho*_*Yue 7

我的代码遇到了同样的问题.尝试此解决方案:

这可能是由两个"cascade.all"引起的.当使用DayPlan实体时,它将同时具有列表和列表,并且两者都具有1:M到DayPlanElementEntry.

因此,当DayPlanElement尝试访问时,两个"cascade.all"可能会发现DayPlanElementEntry已分配给Person,即使它与DayPlanElementEntry相同.

我希望它有所帮助.

最好的,冲


Sur*_*non 7

这可以通过升级到hibernate 4.2.15/4.3.6或更高版本并将以下行添加到persistence.xml来重新解析:

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

有关更多详细信息,请参阅https://hibernate.atlassian.net/browse/HHH-9106


New*_*bie 1

如果这是在测试的上下文中,我建议您在 session.flush() 之后使用 session.clear()。这将有效地清除您的会话缓存,这似乎是问题的核心。

这个问题的潜在原因(我能想到的):

  • 相同的实体副本被添加到不同实体键下的缓存中。在 EventCache.java 中的 put 方法下设置断点以获取更多详细信息。
  • 您正在使用的 hibernate 版本中新引入的错误。