Нарушение уникальных ограничений в Hibernate @ManyToMany Relationship - PullRequest
0 голосов
/ 13 февраля 2020

В моей базе данных 3 объекта, назовем их A, B и C.

A и B разделяют отношения друг с другом. A имеет SortedSet из B с, но B не ссылается на A (коллекция не настроена или не настроена). Итак, у нас есть следующее.

// Inside class A
@ManyToMany
@JoinTable(name = "a_b", 
           joinColumns = {@JoinColumn(name = "a_id")}, 
           inverseJoinColumns = {@JoinColumn(name = "b_id")})
@LazyCollection(LazyCollectionOption.FALSE)
@SortNatural
private SortedSet<B> bSet = new TreeSet<B>();

B и C имеют отношения «один ко многим» друг с другом (от 1 B до многих C с). C имеет B в своей сущности, но B не имеет ссылки на множество C сущностей. Итак, у нас есть следующий

// Inside class C
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "b_id", nullable = false, updatable = true)
protected B b;

У нас есть процесс syn c, который запускает ночное задание для обновления A сущностей и их ассоциаций до B сущностей (что не очень часто меняется ). В итоге получается нечто похожее на следующее (действительно, с DAO, сервисами и т. Д. Все намного сложнее).

// Get the A value to be updated
A aToUpdate = entityManager.find(A.class, idForA); 

// Out of scope of the question, but we need to figure out B via a string field on C
C cValue = myDao.getByProperty("fieldName", fieldValue);

// Determine the B values to set on aToUpdate
B bToSetOnA = cValue.getB();
TreeSet<B> bSet = new TreeSet<>();
bSet.add(bToSetOnA);

// Update aToUpdate
aToUpdate.setBSet(bSet);
aToUpdate = entityManager.merge(aToUpdate);
entityManager.flush();

Когда это происходит, возникает следующая ошибка.

ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (Sync Thread)
Duplicate entry 'myAId-almostMyBId' for key 'uk_a_b'

Одна интересная вещь заключается в том, что almostMyBId на 1 символ меньше реального B ID. Но в таблице a_b отображается только полный идентификатор.

Когда я просматриваю базу кода, на индекс в таблице a_b накладывается ограничение uk_a_b. Это из ликвидазы.

<createIndex indexName="uk_a_b" tableName="a_b" unique="true">
    <column name="a_id"/>
    <column name="b_id"/>
</createIndex>

Если удалить строку aToUpdate.setBSet(bSet);, ошибка исчезнет.

Я добавил логирование и подтвердил, что идентификаторы новых bSet такие же, как и у старых aToUpdate.

Каким-то образом Hibernate, похоже, пытается заново добавить ассоциацию, даже если мы проводим слияние, и ассоциации действительно не изменились.

Я пытался изменить некоторые вещи CascadeType и FetchType тут и там, но, похоже, ошибка не исчезла go. Кто-нибудь имеет представление о том, что происходит?

1 Ответ

0 голосов
/ 18 февраля 2020

Это очень специфично c для моей ситуации, но я решил опубликовать ответ в любом случае, если кто-нибудь прочитает мой вопрос и будет над ним работать.

Другой разработчик в моей команде получил задание ускорение отчета на основе таблиц a и a_b. Чтобы избежать необходимости использовать операторы JOIN и WHERE, разработчик скопировал данные из a_b в новую таблицу (используя предложение WHERE) и добавил триггеры, чтобы при каждом обновлении он вставлялся в новую таблицу. Эта новая таблица имеет ограничение, названное так же, как таблица a_b (а именно uk_a_b). Дублированный случай не был обработан должным образом, поэтому выдается ошибка. Из-за сходства имен, это, казалось, была таблица a_b, вызывающая проблему, когда это была действительно новая таблица. Веселые времена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...