2012-06-01 2 views
3

Possible Duplicate:
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); 

Это работало бы. (Это, конечно, не реальная проблема, но простой пример)

+0

Вы '<генератор class =" назначен "/>', как назначается идентификатор? –

+0

Идентификатор поступает извне, каждый курс всегда вставлен с идентификатором реального мира, с которым я не контролирую. (Это первое число в моем конструкторе) –

ответ

9

В конце я просто использовал merge() вместо save(), похоже, он решает проблему, даже если у меня есть набор объектов, а не просто попытка работать с обычным объектом.

+1

Если в конце обсуждения вы напишете себе ответ и дадите бонус себе вместо того, кто помог вам, тогда никто не хочет вам снова помогать. – Johanna

+5

Ну, это не значит, что ты мне не помог ... Но в конце я использовал что-то еще. Я думал, что должен выбрать ответ в соответствии с тем, что я на самом деле использовал в конце? –

+33

@Johanna - самопринятые ответы не начисляют бонус, поэтому не обвиняйте его в этом. И он прав; в идеале, принятый ответ должен быть тем, который был фактически использован. – Spudley

2

Идентификатор является уникальным ключом для таблицы курса. Каждое значение id может использоваться только один раз. Ваша связь между курсом - m: n.

Когда вы используете разные экземпляры для одного и того же курса (тот же идентификатор), вы пытаетесь вставить две разные строки с одним и тем же идентификатором. Это не сработает. Hibernate запоминает для каждого экземпляра (экземпляр, а не ключевое значение!), Если он уже сохранен, и потому, что вы используете каскад, то в момент сохранения Hibernate смотрит, какие дочерние экземпляры еще не сохранены, и если вы сначала сохраните c1, то c12 еще не сохранен и впоследствии сохранит вашу ошибку.

Решение: Вставьте те же экземпляры курса в оба списка курсов RecommendedSchedule. В любом случае, это те же курсы.

+0

Две таблицы не заполняются одновременно, я получаю Курсы из одного источника, а RecommendedSchedules - из другого. Невозможно ли выполнить эту работу, не заменяя каждый курс рекомендуемого расписания на DB? –

+1

Возможность 1: не каскадировать операции. Возможность 2: удалить «Set» из файла сопоставления, ввести простое свойство 'courseId' типа int вместо этого и для удобства написать метод' readCourses() ', который в дополнительном запросе читает курсы из одного РекомендуемогоSchedule в другом запросе ,Но у вас не может быть двух экземпляров для одного объекта базы данных за один сеанс - если вы изменили один из них, у другого были разные значения, которые затем отражаются на ситуации с db? – Johanna

+0

Я на самом деле только вставляю элементы здесь один раз, а остальные - операции получения. Также я не открываю сеансы между операциями. Думаете, это помогает? –

Смежные вопросы

 Смежные вопросы