【问题标题】:a different object with the same identifier value was already associated with the session [duplicate]具有相同标识符值的不同对象已与会话相关联[重复]
【发布时间】:2012-06-06 16:14:35
【问题描述】:

可能重复:
Hibernate: different object with the same identifier value was already associated with the session

我收到以下错误:

具有相同标识符值的不同对象已与会话关联

我有两种类型的对象,Course 和 RecommendedSchedule,它们有一组课程。 以下是它们的 xml 定义:

<hibernate-mapping>
<class name="database.datatypes.Course" table="courses" lazy="false">
    <id name="id" column="ID">
         <generator class="assigned"/>
    </id>
    <property name="name" type="string"/>
    <property name="date"/>
</class>

<hibernate-mapping>
<class name="database.datatypes.RecommendedSchedule" table="recommended_schedules" lazy="false">
    <id name="id" column="ID">
         <generator class="increment"/>
    </id>
    <set name="courses" table="schedules_courses" cascade="save-update" lazy="false">
        <key column="course_id"/>
        <many-to-many class="database.datatypes.Course"/>
    </set>
    <property name="semester" type="string"/>
    <property name="path" type="string"/>
</class>

基本上,如果我插入两个具有不同集合的推荐系统,但使用相同的课程对象,它可以工作,但如果我做完全相同的事情但使用不同的课程对象(具有相同的值),我会得到错误。

谁知道我做错了什么?

下面是一段失败的代码示例:

Session s = db.factory.openSession();
    Set<Course> set1 = new HashSet<>();
    Set<Course> set2 = new HashSet<>();
    Course c1 = new Course(104167L, "Algebra A");
    Course c2 = new Course(234114L, "Introduction to CS H and M");
    Course c3 = new Course(104012L, "Calculus 1 T");
    Course c4 = new Course(234145L, "Digital Systems");
    Course c12 = new Course(104167L, "Algebra A");
    Course c22 = new Course(234114L, "Introduction to CS H and M");
    Course c32 = new Course(104012L, "Calculus 1 T");
    Course c42 = new Course(234145L, "Digital Systems");
    set1.add(c1);
    set1.add(c2);
    set1.add(c3);
    set2.add(c12);
    set2.add(c22);
    set2.add(c32);
    set2.add(c42);
    RecommendedSchedule r1 = new RecommendedSchedule(set1, "General 3 years", "1");
    RecommendedSchedule r2 = new RecommendedSchedule(set2, "General 4 years", "1");
    Collection<RecommendedSchedule> col = new ArrayList<RecommendedSchedule>();
    Collection<Course> col2 = new ArrayList<Course>();
    col.add(r1);
    col.add(r2);
    col2.add(c12);
    col2.add(c22);
    col2.add(c32);
    col2.add(c42);

    Transaction t = s.beginTransaction();
    s.save(r1);
    s.save(r2);
    t.commit();
    s.close();

如果我这样做了:

set2.add(c1);
set2.add(c2);
set2.add(c3);
set2.add(c4);

它会起作用的。 (这当然不是真正的问题,只是一个简单的例子)

【问题讨论】:

  • &lt;generator class="assigned"/&gt;,ID是怎么分配的?
  • ID 来自外部,每门课程总是插入它的真实世界 ID,我无法控制。 (这是我的构造函数中的第一个数字)

标签: java hibernate set


【解决方案1】:

id 是 Course 表的唯一键。每个 id 值只能使用一次。 Course 之间的关系是 m:n。

当您对同一课程(相同 ID)使用不同实例时,您会尝试插入两个具有相同 ID 的不同行。这是行不通的。 Hibernate 会记住每个实例(实例,而不是键值!)如果它已经保存,并且因为您使用级联,那么在保存时 Hibernate 会查看哪些子实例尚未保存,如果您先保存 c1,那么c12 尚未保存,稍后保存会产生错误。

解决方案:在RecommendedSchedule 的两个课程列表中插入相同的Course 实例。无论如何,它们是相同的课程。

【讨论】:

  • 两张表没有同时填满,我从一个来源获得 Courses,从另一个来源获得RecommendedSchedules。如果不将每个 RecommendedSchedule 的课程替换为 DB 课程,是否就无法完成这项工作?
  • 可能性一:不要级联操作。可能性 2:从映射文件中删除 Set,引入一个简单的 int 类型属性 courseId,并为方便起见编写一个方法 readCourses(),它在一个额外的查询中从另一个查询中的一个 RecommendedSchedule 读取课程。但是你不能在一个会话中为一个数据库实体有两个实例——如果你改变其中一个,另一个有不同的值,那么哪一个反映了数据库的情况?
  • 我这里其实只插入一次,其余都是get操作。此外,我不会在操作之间保持会话打开。认为这有什么帮助?
  • 一个数据库实体每个会话只能附加到一个对象实例。这是 Hibernate 的设计决定。你不能绕过它。
  • 我注意到使用合并而不是保存解决了我的问题。这样做是否存在根本缺陷?
【解决方案2】:

最后我只是简单地使用了merge()而不是save(),似乎它解决了问题,即使我有一组对象,而不仅仅是尝试使用普通对象。

【讨论】:

  • 如果在讨论结束时你给自己写了一个答案,然后把奖金给自己而不是给帮助过你的人,那么没有人愿意再帮助你了。
  • 好吧,不是你没有帮助我……但最后我用了别的东西。我想我应该根据我最终实际使用的内容来选择答案?
  • @Johanna - 自我接受的答案不会获得奖励,所以不要指责他。他的观点是正确的;理想情况下,接受的答案应该是实际使用的答案。
猜你喜欢
  • 2011-03-16
  • 2011-04-02
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 2014-04-16
  • 2013-08-30
相关资源
最近更新 更多