【问题标题】: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 中。

DayPlanElementDayPlanElementEntry 弱实体具有 OneToMany 关系。 java.util.Set 用于保存。 Person 实体也与 DayPlanElementEntry 弱实体的 OneToMany 关系。 java.util.Set 用于保存。 DayPlanDayPlanElementPerson 实体具有由我的应用程序管理的 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
          相关资源
          最近更新 更多