GSON + Hibernate:导致“实体副本已被分配给不同实体”的相同对象。 [英] GSON + Hibernate: Identical objects causing "An entity copy was already assigned to a different entity"

查看:70
本文介绍了GSON + Hibernate:导致“实体副本已被分配给不同实体”的相同对象。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下JSON:

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

使用Gson反序列化它。之后,我需要合并JPA实体:

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

刷新从模型级联到子对象并下到这些国家。
这会导致异常实体副本已被Hibernate分配给不同的实体。



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



两个国家/地区都有相同的值。两者都有相同的hashCode。
这两个国家是相同的,但不是==,因为它们是不同的实例。



这个问题没有帮助我。



我正在使用Hibernate 4.1.3 Final和Gson 2.2

  java.lang.IllegalStateException:实体副本已被分配给不同的实体。 
at org.hibernate.event.internal.EventCache.put(EventCache.java:184)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285)
在org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
在org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
在org.hibernate.internal .SessionImpl.merge(SessionImpl.java:896)
在org.hibernate.engine.spi.CascadingAction $ 6.cascade(CascadingAction.java:288)
在org.hibernate.engine.internal.Cascade。 cascadeToOne(Cascade.java:380)
位于org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
位于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)
在org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:308)
在org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
at org。 hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
在org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
在org.hibernate.engine.spi.CascadingAction $ 6 .cascade(CascadingAction.java:288)
在org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
在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)
A t 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 )
[...]

我该如何解决这个问题通用的方式我不需要知道对象类型和哪些对象逻辑上相同?

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



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

重要提示:

Andrei我提出了很多可能发生的逻辑问题,并将api改为不能获得全部国家,但只是他们的ID会更清楚。我更喜欢这一点,将来会这样做。
因此,安德烈我赢得了赏金。


I have the following JSON:

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

And deserialize it using Gson. After that I need to merge the JPA Entity:

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

The refresh is cascaded from the model to the subObjects and down to the countries. This causes the Exception "An entity copy was already assigned to a different entity" by Hibernate.

It works if I use different countries. It works if I use copy the country instance from one object into the other one so both subObjects references the same instance of that contry.

Both countries have identical values in it. Both have the same hashCode, too. The both countries are equal but not == since they are different instances.

The tipps listed on this question did not help me.

I am using Hibernate 4.1.3 Final and 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)
    [...]

How can I solve this problem in a generic way I don't need to know the object types and which objects are logically identical?

解决方案

Here is my working solution not using merge:

I use reflection to iterate over the fields at binding time. I check if the field is an entity or a collection of entities and then call a findByID if the id if provided in the json or create a new instance of the entity if not to get an attached entity. After that I copy the field values that exists in the json via reflection into the attached entity. I do it recursively to handle relations between the entities. After that I have a completly merged and attached version of my entity with all that attached and merged subobjects. I can save it without any Problems

Important note:

Andrei I suggested a lot of logical problems that could occur and changing the api to not get the full countries, but just their IDs would be more clearly. I prefer this and will do this in the future. Therefore Andrei I earned the bounty.

这篇关于GSON + Hibernate:导致“实体副本已被分配给不同实体”的相同对象。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆