一尘不染

GSON +休眠:导致“一个实体副本已分配给另一个实体”的相同对象

hibernate

我有以下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出现异常“已将实体副本分配给其他实体”。

如果我使用其他国家/地区,则可以使用。如果我使用将国家/地区实例从一个对象复制到另一个对象,那么这两个子对象都引用该对象的同一实例,则该方法有效。

两国具有相同的价值观。两者也具有相同的hashCode。两国是平等的,但不是==,因为它们是不同的情况。

我正在使用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)
    [...]

我该如何以通用的方式解决此问题,而无需知道对象类型以及哪些对象在逻辑上是相同的?


阅读 160

收藏
2020-06-20

共1个答案

一尘不染

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

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

重要的提示:

安德烈(Andrei)我提出了许多可能发生的逻辑问题,并且更改了api使其无法获得完整的国家/地区,但仅凭其ID会更清楚。我喜欢这个,将来会做。因此,安德烈·我赢得了赏金。

2020-06-20