org.hibernate.exception.ConstraintViolationException: не удалось выполнить пакетное обновление JDBC [из-за уникального ограничения]

Ошибка: org.hibernate.exception.ConstraintViolationException: не удалось выполнить пакетное обновление JDBC

java.sql.BatchUpdateException: повторяющаяся запись "24-0-es_reservation_detail" для ключа "questionId_referenceId_referenceType"

Я собираюсь сохранить объект бронирования. Этот объект бронирования содержит коллекцию объектов reservaitonDetails, а каждый объект сведений о бронировании содержит коллекцию объектов questionAnswers.

Основная проблема заключается в уникальном ограничении таблицы questionAnswer.

Unqiue Constraint: question_id, reference_id, reference_type.

Когда система сохраняет объект резервирования: система сначала сохраняет резервирование, затем собирает детали резервирования, а затем ответы на все вопросы с 0 (reference_id). При добавлении вопроса с идентификатором ссылки 0 система выдает исключение, поскольку нарушается уникальное ограничение.

ReservationDetail.hbm.xml

.............
.............
<set name="questionAnswers" lazy="true" cascade="all-delete-orphan" where="reference_type = 'es_reservation_detail'">
        <key column="reference_id"/>
        <one-to-many class=".....QuestionAnswerDTO" />
    </set>
.............
.............

Пример:

Если мы сохраним сбор в деталях бронирования

1. insert into reservation......... (reservation id = 1)

2. insert into reservation_detail.......   (reservation detail id = 1)
3. insert into reservation_detail.......   (reservation detail id = 2)

4. insert into question_answer..... (referece_type='RD' referece_id=0, question_id =1) - For Reservation Detail id =  1
5. insert into question_answer..... (referece_type='RD' referece_id=0, question_id =1) - For Reservation Detail id =  1

6. update reservation_detail set reservation_id = ? where reservation_detail_id = ? (reservation_id = 1, reservation_detail_id = 1)
7. update reservation_detail set reservation_id = ? where reservation_detail_id = ? (reservation_id = 1, reservation_detail_id = 2)

8. update question_answer set reference_id = ? where question_answer_id = ? (reference_id = 1 and question_answer_id =1)
9. update question_answer set reference_id = ? where question_answer_id = ? (reference_id = 2 and question_answer_id =2)

Когда система выполнит пункт (5) скрипта. Система будет через исключение нарушения ограничений.

Есть ли какой-нибудь способ, которым спящий режим обновляет reference_id в question_answer (таблице) непосредственно перед созданием следующего запроса на вставку.

Сценарий 8 должен запускаться после 4-го сценария

Скрипт 9 должен запускаться после 5-го сценария


person Ishwar Lal    schedule 02.07.2015    source источник
comment
какой тип генератора вы используете, кажется, идентификатор не увеличивается, по вопросу и ссылочному объекту   -  person pappu_kutty    schedule 02.07.2015
comment
Когда я прочитал документы о спящем режиме. Hibernate сначала вставляет дочерние объекты (questionAnswer) со ссылкой null или 0, а затем hibernate выполняет запрос на обновление (см. сценарии 8 и 9).   -  person Ishwar Lal    schedule 02.07.2015
comment
два разных объекта не могут иметь одинаковый идентификатор, я не знаю, где вы поняли, вопрос_ид и ссылка_ид являются составными ключами?   -  person pappu_kutty    schedule 02.07.2015
comment
(question_id, reference_id, reference_type) — составной ключ для таблицы question_asnwer.   -  person Ishwar Lal    schedule 02.07.2015
comment
Я использую генератор удостоверений в отображении деталей резервирования hbm.   -  person Ishwar Lal    schedule 02.07.2015
comment
какова связь между ссылкой и таблицей question_answer, многие ко многим?   -  person pappu_kutty    schedule 02.07.2015
comment
отношение один ко многим между question_answer и reservation_detail. (Один - бронирование_деталь : много : вопрос_ответ). reference_id (столбец) в таблице (question_answer) является внешним ключом   -  person Ishwar Lal    schedule 02.07.2015


Ответы (2)


Опция Hiberate cascade вставляет дочерние объекты с внешним ключом, если вы правильно сопоставили родительский класс в дочернем сопоставлении. Если вы не сопоставили родительский класс в дочернем сопоставлении, а как Integer reference_id, тогда внешний ключ будет обновлен с использованием отдельного запроса на обновление:

 update question_answer set reference_id = ? where question_answer_id = ?

Если вы не можете указать объект родительского класса в дочернем сопоставлении, вы можете использовать обходной путь. Вы можете установить reference_id как разрешенное null (в таблице), и вам нужно установить referenceId=null; в дочернем объекте. Затем каскад Hibernate вставит дочерние объекты с null внешним ключом, а следующий вызов вызовет запрос на обновление, чтобы установить referenceId сгенерированный внешний ключ.

Примечание. Значения null в уникальном столбце не считаются повторяющимися значениями, если они появляются более одного раза.

person Ilyas Soomro    schedule 02.07.2015

Скорее всего, вы не определили в объекте QuestionAnswerDTO ссылку на основной объект, которым является ReservationDetails. Вы должны настроить @MAnyToOne в QuestionAnswerDTO, который имеет в качестве @JoinColumn "reference_id" что-то вроде этого

@ManyToOne
 @JoinColumn(name="persistence_id")
 private ReservationDetail reservationDetail;

а затем задайте для свойства reservationDetail фактический объект ReservationDetail, которому он принадлежит.

Тогда JPA будет знать, что ему нужно заполнить reference_id ссылкой на REservationDetails. В противном случае он рассматривает его как любое другое поле

person iullianr    schedule 02.07.2015
comment
В основном нет проблем со ссылками. Эта проблема связана с последовательностью скриптов, которые создаются в спящем режиме. Мне нужно обновить идентификатор ссылки сразу после вставки. Но спящий режим генерирует сценарии обновления после всех вставок (как уже упоминалось в вопросе). - person Ishwar Lal; 02.07.2015
comment
hibernate генерирует сценарии на основе конфигураций ваших объектов и отношений между ними. Пока вы правильно настраиваете все отношения, вам не нужно вмешиваться в то, что делает Hibernate на уровне SQL. Hibernate будет генерировать скрипты таким образом, чтобы оптимизировать взаимодействие с базой данных. - person iullianr; 02.07.2015