带有 Hibernate 4 和 ManyToOne 级联的 IllegalStateException [英] IllegalStateException with Hibernate 4 and ManyToOne cascading

查看:20
本文介绍了带有 Hibernate 4 和 ManyToOne 级联的 IllegalStateException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这两门课

MyItem 对象:

@Entity
public class MyItem implements Serializable {

    @Id
    private Integer id;
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Component defaultComponent;
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Component masterComponent;

    //default constructor, getter, setter, equals and hashCode
}

组件对象:

@Entity
public class Component implements Serializable {

    @Id
    private String name;

    //again, default constructor, getter, setter, equals and hashCode
}

我正在尝试使用以下代码保留这些代码:

And I'm tring to persist those with the following code:

public class Test {

    public static void main(String[] args) {
        Component c1 = new Component();
        c1.setName("comp");
        Component c2 = new Component();
        c2.setName("comp");
        System.out.println(c1.equals(c2)); //TRUE

        MyItem item = new MyItem();
        item.setId(5);
        item.setDefaultComponent(c1);
        item.setMasterComponent(c2);

        ItemDAO itemDAO = new ItemDAO();
        itemDAO.merge(item);
    }
}

虽然这适用于 Hibernate 3.6,但 Hibernate 4.1.3 会抛出

While this works fine with Hibernate 3.6, Hibernate 4.1.3 throws

Exception in thread "main" 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.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:213)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:282)
        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 sandbox.h4bug.Test$GenericDAO.merge(Test.java:79)
        at sandbox.h4bug.Test.main(Test.java:25)

数据库后端是 h2(但 hsqldb 或 derby 也是如此).我做错了什么?

Database backend is h2 (but the same happens with hsqldb or derby). What am I doing wrong?

推荐答案

我遇到了同样的问题,这是我发现的:

I had the same problem, and this is what I found:

merge 方法遍历你要存储的对象的图,对于这个图中的每个对象,它从数据库中加载它,所以它对每个对象都有一对(持久实体,分离实体)图,其中分离实体是要存储的实体,持久实体是从数据库中获取的.(在该方法以及错误消息中,持久实体被称为复制").然后将这些对放在两个映射中,一个以持久实体为键,分离实体为值,另一个以分离实体为键,持久实体为值.

The merge method traverses the graph of the object that you want to store, and for each object in this graph it loads it from the database, so it has a pair of (persistent entity, detached entity) for each object in the graph, where detached entity is the entity that is going to be stored, and persistent entity is gotten from the database. (In the method, as well as in the error message the persistent entity is known as 'copy'). Then these pairs are put in two maps, one with the persistent entity as key and the detached entity as value, and one with the detached entity as key and the persistent entity as value.

对于每对这样的实体,它会检查这些映射,以查看持久实体是否像以前一样映射到相同的分离实体(如果它已经被访问过),反之亦然.当您获得一对实体,其中对持久实体执行 get 返回一个值,但从另一个映射获取,分离实体返回 null,这意味着您已经将持久实体与分离实体链接具有不同哈希码的实体(如果您没有覆盖哈希码方法,则基本上是对象标识符).

For each such pair of entites, it checks these maps, to see if the persistent entity maps to the same detached entity as before (if it has already been visited), and vice versa. This problem occurs when you get a pair of entities where doing a get with the persistent entity returns a value, but a get from the other map, with the detached entity returns null, which means that you have already linked the persistent entity with a detached entity with a different hashcode (basically the object identifier if you have not overridden the hashcode-method).

TL;DR,您有多个对象具有不同的对象标识符/哈希码,但具有相同的持久性标识符(因此引用相同的持久性实体).这在较新版本的 Hibernate4 中显然不再被允许(据我所知为 4.1.3.Final 及更高版本).

TL;DR, you have multiple objects with different object identifiers/hashcode, but with the same persistence identifier (thus referencing the same persistent entity). This is appearantly no longer allowed in newer versions of Hibernate4 (4.1.3.Final and upwards from what I could tell).

错误信息不是很好的imo,它真正应该说的是:

The error message is not very good imo, what it really should say is something like:

一个持久化实体已经分配给另一个分离实体

同一个持久化实体对应的多个分离对象

这篇关于带有 Hibernate 4 和 ManyToOne 级联的 IllegalStateException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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