hibernate错误:具有相同标识符值的不同对象已经与会话相关联
我基本上在这个configuration中有一些对象(真正的数据模型有点复杂):
- A与B有多对多的关系(B有
inverse="true"
) - B与C有着多对一的关系(我把
cascade
设置为"save-update"
) - C是一种types/类别表。
另外,我应该提到主键是由数据库在保存时生成的。
有了我的数据,我有时会遇到A有一组不同的B对象的问题,这些B对象引用同一个C对象。
当我调用session.saveOrUpdate(myAObject)
,我得到一个hibernate错误,说: "a different object with the same identifier value was already associated with the session: C"
。 我知道hibernate不能在同一个会话中插入/更新/删除同一个对象两次,但是有没有办法解决这个问题呢? 这似乎不是那种罕见的情况。
在我研究这个问题的时候,我已经看到人们使用session.merge()
,但是当我这样做的时候,任何“冲突的”对象都被作为空白对象插入到数据库中,所有的值都设置为null。 显然这不是我们想要的。
另外一个我忘记提到的是(由于体系结构的原因,我无法控制),每个读或写需要在一个单独的会话中完成。
很可能是因为B对象不是指同一个Java C对象实例。 他们指的是数据库中的同一行(即相同的主键),但它们是不同的副本。
所以发生的事情是,pipe理实体的Hibernate会话将跟踪哪个Java对象与具有相同主键的行相对应。
一种select是确保引用同一行的对象B的实体实际上是指C的同一对象实例。或者closures该成员variables的级联。 当B坚持时,这种方式不是C。 不过,您将不得不手动保存C. 如果C是一个types/类别表,那么这样做可能是有道理的。
只要设置级联MERGE,这应该做的伎俩。
通过使用以下命令将对象ID从Hibernate分配给数据库的任务:
<generator class="native"/>
这解决了我的问题。
你只需要做一件事。 运行session_object.clear()
,然后保存新的对象。 这将清除会话(如适当命名),并从会话中删除违规的重复对象。
解决上述问题的一种方法是重写hashcode()
。
同时在保存之前和之后刷新hibernate会话。
getHibernateTemplate().flush();
显式设置分离的对象为null
也有帮助。
刚刚遇到这个消息,但在C#代码。 不知道是否相关(尽pipe相同的错误信息)。
我正在用断点debugging代码,并在debugging器处于断点处时通过私有成员扩展某些集合。 重新运行代码而不挖掘结构使错误消息消失。 看起来,查看私有惰性加载集合的行为使NHibernate加载了当时不应该加载的东西(因为它们在私有成员中)。
代码本身包装在一个相当复杂的事务中,可以更新大量logging和许多依赖项作为该事务的一部分(导入过程)。
希望能够给遇到问题的任何人提供线索。
我同意@Hemant kumar,谢谢你差别很大。 根据他的解决scheme,我解决了我的问题。
例如:
@Test public void testSavePerson() { try (Session session = sessionFactory.openSession()) { Transaction tx = session.beginTransaction(); Person person1 = new Person(); Person person2 = new Person(); person1.setName("222"); person2.setName("111"); session.save(person1); session.save(person2); tx.commit(); } }
Person.java
public class Person { private int id; private String name; @Id @Column(name = "id") public int getId() { return id; } public void setId(int id) { this.id = id; } @Basic @Column(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } }
这个代码总是在我的应用程序中出错: A different object with the same identifier value was already associated with the session
,后来,我发现我自动增加了我的主键!
我的解决scheme是将此代码添加到您的主键:
@GeneratedValue(strategy = GenerationType.AUTO)
将注释@GeneratedValue添加到要插入的bean。
我有这个错误几天一去,我花了太多的时间来修复这个错误。
public boolean save(OrderHeader header) { Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); try { session.save(header); for (OrderDetail detail : header.getDetails()) { session.save(detail); } transaction.commit(); session.close(); return true; } catch (HibernateException exception) { exception.printStackTrace(); transaction.rollback(); return false; } }
在我得到这个错误之前,我没有提到OrderDetil对象的ID生成types。 当没有生成Orderdetails的id时,它将每个OrderDetail对象的Id保持为0。 这是什么#jbx解释。 是的,这是最好的答案。 这一个例子是如何发生的。
尝试放置您的查询的代码之前。 这解决了我的问题。 例如改变这个:
query1 query2 - get the error update
对此:
query2 query1 update
在Hibernate中查找“Cascade”属性并删除它。 当你设置“Cascade”可用时,它将调用其他与相关类关联的实体的其他操作(保存,更新和删除)。 所以相同的身份价值将会发生。 它与我合作。
在调用更新查询之前,您可能不会设置对象的标识符。