5

Possible Duplicate:
Hibernate: different object with the same identifier value was already associated with the session

I get the following error:

a different object with the same identifier value was already associated with the session

I have two types of objects, Course and RecommendedSchedule which has a set of courses. Here are their xml definitions:

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

and

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

Basically if i insert two recommended systems with different sets, but using the same Course objects, it works, but if i do the exact same thing but use different Course objects (with the same values) i get the error.

Anyone knows what I'm doing wrong?

Here is an example for a piece of code that fails:

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();

if i did instead:

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

It would've worked. (This of course isn't the real issue, but a simple example)

Community
  • 1
  • 1
gil_bz
  • 478
  • 1
  • 5
  • 16

2 Answers2

10

In the end i simply used merge() instead of save(), seems it solves the problem even though i have a set of objects and not just trying to work with a normal object.

gil_bz
  • 478
  • 1
  • 5
  • 16
  • 1
    If at the end of the discussion you write yourself an answer and give the bonus to yourself instead to them who helped you, then nobody likes to help you again. – Johanna Jun 05 '12 at 08:42
  • 8
    Well it isn't that you didn't help me... But in the end i used something else. I thought i should pick the answer according to what I actually used in the end? – gil_bz Jun 05 '12 at 10:50
  • 36
    @Johanna - self-accepted answers don't score a bonus, so don't accuse him of that. And his point is right; the accepted answer should ideally be the one that was actually used. – Spudley Jun 05 '12 at 11:17
2

The id is the unique key for the Course table. Each id value can be used only once. Your relation between Course is m:n.

When you use different instances for the same course (same id), then you try to insert two different rows with the same id. This can't work. Hibernate remembers for each instance (instance, not key value!) if it is already saved, and because your using cascade, then in the moment of saving Hibernate looks which child instances are not saved yet, and if you save c1 first, then c12 is not yet saved and saving it later produces your error.

Solution: Insert the same instances of Course in both courses lists of RecommendedSchedule. They are the same courses anyway.

Johanna
  • 5,223
  • 1
  • 21
  • 38
  • The two tables are not filled at the same time, I get the Courses from one source, and the RecommendedSchedules from another. Is there no way to make this work without substituting each RecommendedSchedule's Courses with the DB ones? – gil_bz Jun 01 '12 at 13:12
  • 1
    Possibility 1: Do not cascade the operations. Possibility 2: Remove the `Set` from the mapping file, introduce a simple property `courseId` of type int instead and for convenience write a method `readCourses()` which in an extra query reads the courses from one RecommendedSchedule in a different query. But you can't have two instances for one database entity in one session - if you'd change one of them, the other had different values, which one reflects to the db situation then? – Johanna Jun 01 '12 at 13:31
  • I actually only insert items here once and the rest are get operations. Also i don't keep sessions open between operations. Think this helps in any way? – gil_bz Jun 01 '12 at 13:57
  • 1
    One database entity can be attached to only one object instance per session. This is a design decision of Hibernate. You can't go around it. – Johanna Jun 01 '12 at 14:18
  • I noticed that using merge instead of save solved my problem. Is there a fundamental flaw in doing this? – gil_bz Jun 04 '12 at 13:26
  • You have two instances c1 and c12 for the same database entity. That's potentially dangerous. Lets assume you first load both c1 and c12, then you modify c1 and save it to the database, and after that you modify c12 and save it to the database. Result: The modification in c1 is lost. (In your relatively simple example this problem does not appear.) Another thing is, the merge might produce a superfluous select or insert statement for the course c12. – Johanna Jun 04 '12 at 15:53
  • Well for the current usage merge will work then, but i see the error of my ways. Thanks! – gil_bz Jun 04 '12 at 18:14