HiAll,
我目前正在尝试了解,我的编码和实体模型有什么问题 我使用hibernate 4.2进行CRUD操作,只使用Generic DAO模式和带有级联ALL和orphanRemoval = true的带注释实体。 我有与 DayPlanElement 弱实体的OneToMany关系的 DayPlan 实体。 DayPlanElement 保存在java.util.Set中。每个 DayPlanElement 都有一个属性“order”。
DayPlan 与实体 Person 之间也有OneToMany关系。实体 Person 保存在java.util。列表中。
DayPlanElement 与 DayPlanElementEntry 弱实体具有OneToMany关系。 java.util.Set用于保存。 Person 实体也与 DayPlanElementEntry 弱实体的OneToMany关系。 java.util.Set用于保存。 DayPlan , DayPlanElement 和 Person 实体拥有由我的应用程序管理的ID作为String。 DayPlanElementEntry 弱实体具有使用EmbeddedId注释的复合Id:DayPlanElementEntryId,包含parentPersonId和dayPlanElementId。它
换句话说,想象一下,存在一个表,代表日计划。列是从0到24的小时数。行是人员,必须从日计划开始操作。每列都是DayPlanElement实体。每一行都是Person实体。每个单元格都是DayPlanElementEntry实体。
如果我只是添加到表新元素(也是人)并删除它(也从列表中删除它然后调用DayPlanDAO.merge(dayPlan) - 我希望在级联和orphanRemoval) - 我没有问题。
只有当我尝试重新排序给定的Persons(只是删除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)
我去处理EventCache,找到问题解决方案,只检查实现的equals()和hashCode()方法 - 没有成功: - (( 注意,我使用equals()方法Id。例如,DayPlanElementEntry的复合ID。该id由hashCode()使用。我只是不明白错误信息,三次输出相同的属性 - ids!
我找到了事件缓存的test class,但现在我不明白以下用例测试:
@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;
}
}
我们有 Id = 1 的简单实体entity1,然后我们坚持它。然后我们创建Simple实体copy1并将其作为值放入事件缓存中。使用持久化实体* 1 *作为关键。 然后我们使用 Id = 2 创建一个简单实体* 2 *,保留它,然后创建ID为2的副本* 2 *实体并将其作为值放入事件缓存中。使用持久性 entity2 作为关键。 为什么这种情况是错误的,为什么会出现这种情况,必须抛出IllegalStateException ??
感谢您的帮助!
答案 0 :(得分:10)
对于Hibernate版本4.3.4及其周围,有一个修复。只需添加此工件:
<dependency>
<groupId>com.intersult</groupId>
<artifactId>jpa-fix</artifactId>
<version>1.1</version>
</dependency>
此修补程序将MergeEventListener替换为处理此类合并的MergeEventListener。
答案 1 :(得分:6)
我的代码遇到了同样的问题。试试这个解决方案:
这可能是由两个“cascade.all”引起的。当使用DayPlan实体时,它将同时具有列表和列表,并且两者都具有1:M到DayPlanElementEntry。
因此,当DayPlanElement尝试访问时,两个“cascade.all”可能会发现DayPlanElementEntry已分配给Person,即使它与DayPlanElementEntry相同。
我希望它有所帮助。
最佳, 冲
答案 2 :(得分:6)
可以通过升级到hibernate 4.2.15 / 4.3.6或更高版本并将以下行添加到persistence.xml来重新解析:
<property name="hibernate.event.merge.entity_copy_observer" value="allow"/>
答案 3 :(得分:1)
如果这是在测试的上下文中,我建议您使用session.clear()跟随session.flush()。这将有效地清除您的会话缓存,这似乎是问题的核心。
这个问题的潜在原因(我能想到):
答案 4 :(得分:0)
项目和组件之间的关系是单向还是双向?如果它是双向的,请确保没有Cascade.MERGE调用返回到Item。
从您的关系中删除CascadeType.Merge
答案 5 :(得分:0)
在jpa配置文件中添加以下内容将解决问题。
在多对多关系中,如果同一实体在执行与已存在实体的合并操作时重复,则hibernate将无法区分它们,直到我们帮助他获得差异。
properties.put("hibernate.event.merge.entity_copy_observer", "allow");