Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate GSON&x2B;休眠:相同的对象导致“休眠”;实体副本已分配给另一个实体";_Hibernate_Jpa_Gson - Fatal编程技术网

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

Hibernate GSON&x2B;休眠:相同的对象导致“休眠”;实体副本已分配给另一个实体";,hibernate,jpa,gson,Hibernate,Jpa,Gson,我有以下JSON: { id: 123, subObjects: [ { id: 564, name: "foo", contry: { id: 1, name: "Germany" } }, { id: 777, name:

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

如果我使用不同的国家,它是有效的。 如果使用“将国家/地区实例从一个对象复制到另一个对象中”,这样两个子对象都会引用该国家/地区的同一实例,则该方法有效

这两个国家都有相同的价值观。两者的哈希代码也相同。 这两个国家是平等的,但不是==因为它们是不同的例子

上面列出的提示对我没有帮助

我使用的是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)
    [...]

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

您是否尝试使用方法分离所有实体?我认为,如果您分离所有实体,您将能够进行
合并

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

该更改是在4.2.x版本中添加的,您可以查看Hibernate Git for EventCache上的提交日志以了解更改和EventCacheTest以重现该问题


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

我认为这样的行为超出了JPA或Hibernate的范围,这就是为什么Hibernate会抛出这个异常:因为它不知道该做什么。我想说的是,您应该避免在实体图中出现相同的实例,或者干扰GSON级别(这似乎也不支持这样的功能),或者在DB中合并实体图之前。

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

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

重要提示:

Andrei I提出了许多可能发生的逻辑问题,并更改api以不获取完整的国家/地区信息,但他们的ID会更清晰。我更喜欢这样,将来也会这样做。
因此,Andrei I获得了奖金。

@AndreiI升级不是一个选项,因为我使用的框架(play 1.2.x)需要特定版本,因为它们使用的补丁程序。我真的需要用一种通用的方法来解决它,因为我对不同的实体有相同的情况,是的,我需要将大型对象从Web服务器传输到客户端的mvc javascript框架(AngularJS),并将它们存储回服务器。这些对象代表着复杂的公司数据。你有没有想过,当两个国家的ID相同,但名称不同时,会发生什么行为?因为这个问题本身并不容易回答,所以我建议您不要接受来自接口的所有内容,而是使用加载ID的DTO。此外,您可能过于信任用户界面。只需考虑添加一个具有不可抗拒ID的国家或一个不允许在该接口中使用的国家。这意味着您必须验证数据,而不是简单地将其合并到数据库中。此应用程序的用户是100%受信任的管理用户,不具备以异常方式修改数据所需的知识,但确实需要验证。在我的情况下,他们不需要修改方案,但需要选择正确的方案。其他情况可能需要进行更多的编译才能实现。在我的例子中,在该对象中获取contries的ID可能是不合适的,而hibernate可以完成其余的工作,但前提是它们是同一个实例。在具有相同ID的对象中存储不同值时的行为应该引发异常,因为在我的情况下,这是无效数据,因此是一个错误的请求。我认为这种行为完全超出了JPA或Hibernate的范围,这就是为什么Hibernate会抛出这个异常:因为它不知道该做什么。我想说的是,您应该避免在实体图中使用相同的实例,或者干扰GSON级别(这似乎也不支持这样的功能),或者在DB中合并实体图之前。当从单个json一次反序列化所有对象时,它们都应该分离,不是吗?对我来说很有帮助,但我是从junit测试开始工作的谢谢,但是升级hibernate不是一个选项。我正在使用的框架(play 1.2.x)使用了hibernate的补丁版本,我不能简单地使用另一个hibernate版本。Dozer mapper Git用户解决了这个问题,将@Transactional注释添加到他的测试类中,哦,不,我不是建议你必须升级hibernate,但是您可以查看测试代码来确定真正的问题。