IllegalStateException与Hibernate 4和ManyToOne级联 [英] IllegalStateException with Hibernate 4 and ManyToOne cascading

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

问题描述



  @Entity 
public class MyItem实现Serializable {

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

//默认构造函数,getter,setter,equals和hashCode
}

组件对象:

  @Entity 
公共类实现Serializable {

@Id
私有字符串名称;

//默认构造函数,getter,setter,equals和hashCode
}

我试图用下面的代码来坚持:

  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 throws

 线程main中的异常java.lang.IllegalStateException:实体副本已被分配给不同的实体。在org.hibernate.event.internal.EventCache.put(EventCache.java:184)

在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(级联。 java:208)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBef oreSave(AbstractSaveEventListener.java:423)
在org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:213)
在org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener。的java:282)$在org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151 b $ b)
。在org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
在org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:904)
在org.hibernate.internal.SessionImpl.merge(SessionImpl.java:888)
在org.hibernate .internal.SessionImpl.merge(SessionImpl.java:892)
在org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:874)在sandbox.h4bug.Test $ GenericDAO.merge
(测试.java:79)
在sandbox.h4bug.Test.main(Test.java:25)

数据库后端是h2(但与hsqldb或derby相同)。我做错了什么?

解决方案

我有同样的问题,而这是我发现的:



合并方法遍历要存储的对象的图形,并且为此图形中的每个对象从数据库加载它,因此它有一对(持久实体,分离实体)为图中的每个对象,其中分离的实体是将要存储的实体,并且持久实体是从数据库中获取的。 (在该方法中,以及错误消息中,持久实体被称为'复制')。然后将这些对放在两个映射中,一个以持久化实体作为键,以分离实体作为值,另一个以分离实体作为键,持久化实体作为值。



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

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



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

持久实体已经被分配给不同的分离实体





对应于相同持久实体的多个分离对象


I've got those two classes

MyItem Object:

@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
}

Component Object:

@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);
    }
}

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)

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:

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.

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, 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).

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

A persistent entity has already been assigned to a different detached entity

or

Multiple detached objects corresponding to the same persistent entity

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

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