GSON + Hibernate:导致“实体副本已分配给不同实体”的相同对象

时间:2013-11-22 14:07:35

标签: hibernate jpa gson

我有以下JSON:

{
    id: 123,
    subObjects: [
        {
            id: 564,
            name: "foo",
            contry: {
                id: 1,
                name: "Germany"
            }
        },
        {
            id: 777,
            name: "bar",
            contry: {
                id: 1,
                name: "Germany"
            }
        }
    ]   
}

使用Gson对其进行反序列化。之后我需要合并JPA实体:

Model model = new Gson().fromJson(json, modelClass);
model = entityManager.merge(model)

刷新从模型级联到子对象并向下到国家/地区。 这导致异常“Hibernate已将实体副本分配给不同的实体。”

如果我使用不同的国家,它会起作用。 如果我将国家实例从一个对象复制到另一个对象中,则它可以工作,因此两个子对象都引用该contry的相同实例。

这两个国家都有相同的价值观。两者都具有相同的hashCode。 这两个国家是平等但不是==,因为它们是不同的实例。

this question上列出的标签对我没有帮助。

我正在使用Hibernate 4.1.3 Final和Gson 2.2

java.lang.IllegalStateException: An entity copy was already assigned to a different entity.
    at org.hibernate.event.internal.EventCache.put(EventCache.java:184)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
    at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
    at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:409)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:326)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
    at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:439)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:904)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:888)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:892)
    at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:874)
    at play.db.jpa.GenericModel.merge(GenericModel.java:234)
    [...]

如何以通用方式解决此问题我不需要知道对象类型以及哪些对象在逻辑上相同?

4 个答案:

答案 0 :(得分:2)

我认为这些行为完全超出了JPA或Hibernate的范围,这就是为什么Hibernate会抛出异常:因为它不知道该怎么做。我想说的是,你应该避免实体图中的相等实例,要么干扰GSON的级别(也似乎不支持这样的特性),要么就是在DB中合并实体图之前。

答案 1 :(得分:2)

这是我的工作解决方案,不使用合并:

我使用反射在绑定时迭代字段。我检查字段是实体还是实体集合,如果id在json中提供,则调用findByID,如果不获取附加实体,则创建实体的新实例。 之后,我通过反射将存在于json中的字段值复制到附加实体中。 我递归地处理实体之间的关系。 在那之后,我有一个完全合并和附加的我的实体版本与所有附加和合并的子对象。 我可以毫无问题地保存它

重要提示:

安德烈我提出了许多可能发生的逻辑问题并且改变了api而没有获得完整的国家,但只是他们的ID会更清楚。我更喜欢这个,将来也会这样做。 因此,安德烈我获得了赏金。

答案 2 :(得分:1)

您是否尝试使用clear方法对所有实体进行分离?我想如果你分离了所有实体,你将能够做merge

答案 3 :(得分:0)

有人在Hibernate Jira中打开了一张票,以便在发生此错误时添加更多信息

HHH-7605

在4.2.x版本中添加了更改,你可以看一下Hibernate的Git for EventCache for commit for change和EventCacheTest来重现问题

HHH-7605 Event cache descriptive log messages

我希望这可以帮助您找到问题。