【问题标题】:Hibernate: An entity copy was already assigned to a different entity休眠:实体副本已分配给不同的实体
【发布时间】:2013-07-13 21:06:15
【问题描述】:

大家好,

我目前正在尝试了解,我的编码和实体模型有什么问题 我使用休眠 4.2 进行 CRUD 操作,仅使用 Generic DAO 模式和带有级联 ALL 和 orphanRemoval=true 的注释实体。 我的 DayPlan 实体与 DayPlanElement 弱实体具有 OneToMany 关系。 DayPlanElement 保存在 java.util.Set 中。每个DayPlanElement都有一个属性“order”。

DayPlan 还与实体 Person 具有 OneToMany 关系。实体 Person 保存到 java.util.List 中。

DayPlanElement 与 DayPlanElementEntry 弱实体具有 OneToMany 关系。 java.util.Set 用于保存。 Person 实体也与 DayPlanElementEntry 弱实体的 OneToMany 关系。 java.util.Set 用于保存。 DayPlan、DayPlanElement 和 Person 实体具有由我的应用程序管理的 ID 作为字符串。 DayPlanElementEntry 弱实体有一个复合 Id:DayPlanElementEntryId 用 EmbeddedId 注解,包含 parentPersonId 和 dayPlanElementId。它

换句话说,想象一下,存在一张表,代表一天的计划。列是从 0 到 24 的小时数。行是必须从日计划进行操作的人员。每列都是 DayPlanElement 实体。每行都是 P​​erson 实体。每个单元格都是 DayPlanElementEntry 实体。

如果我只是向表中添加新元素(也是 Persons)并删除它(也从 List 中删除它,然后调用 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()方法——没有成功:-(( 请注意,我将 ID 用于 equals() 方法。例如 DayPlanElementEntry 的复合 id。该 id 由 hashCode() 使用。我只是不明白错误消息,三次将输出相同的属性 - id!

我找到了用于事件缓存的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,然后我们将其持久化。然后我们创建简单实体 copy1 并将其作为值放入事件缓存中。作为键使用的持久化实体*1*。 然后我们创建一个 Id=2 的 Simple entity*2* ,持久化它,然后创建 id 为 2 的 copy*2* 实体并将其作为值放入事件缓存中。使用持久化的 entity2 作为关键。 为什么这种情况是错误的,为什么必须抛出 IllegalStateException?

感谢您的帮助!

【问题讨论】:

  • 同样的问题!请,如果您找到解决方案 - 发布它

标签: hibernate merge


【解决方案1】:

对于 Hibernate 4.3.4 及更高版本,有一个修复程序。只需添加这个工件:

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

此修复将 MergeEventListener 替换为处理此类合并的 MergeEventListener。

【讨论】:

  • 等等,什么?这确实解决了我的休眠合并问题!它是如何工作的?你有这个修复的任何官方文档吗?
【解决方案2】:

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

&lt;property name="hibernate.event.merge.entity_copy_observer" value="allow"/&gt;

更多详情请参考https://hibernate.atlassian.net/browse/HHH-9106

【讨论】:

    【解决方案3】:

    我的代码也有同样的问题。试试这个解决方案:

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

    所以当 DayPlanElement 尝试访问它时,两个“cascade.all”可能会发现 DayPlanElementEntry 已分配给 Person,即使它是相同的 DayPlanElementEntry。

    希望对你有帮助。

    最好, 冲

    【讨论】:

    • 花了两个小时寻找解决方案,这太容易了,同时又很愚蠢....谢谢
    • 那么解决方案是什么?我有同样的问题 D:
    【解决方案4】:

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

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

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

    【讨论】:

      【解决方案5】:

      在 jpa 配置文件下面添加它会解决问题。

      在多对多关系中,如果同一个实体在与已经存在的实体执行合并操作时重复,休眠将无法区分它们,直到我们帮助他获得差异。

      properties.put("hibernate.event.merge.entity_copy_observer", "allow");
      

      【讨论】:

        【解决方案6】:

        项目和组件之间的关系是单向的还是双向的?如果它是双向的,请确保您没有 Cascade.MERGE 调用返回到 Item。

        从你的关系中移除 CascadeType.Merge

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-22
          • 1970-01-01
          • 2013-01-17
          相关资源
          最近更新 更多