Hibernate - очистка коллекции с помощью all-delete-orphan и последующее добавление к ней вызывает ConstraintViolationException - PullRequest
13 голосов
/ 14 января 2010

У меня есть эти сущности

class Foo{
    Set<Bar> bars;
}

class Bar{
    Foo parent;
    String localIdentifier;
}

С этим отображением (извините, аннотаций нет, я старомоден):

<class name="Foo">
    ...
    <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true">
        <key>...</key>
        <one-to-many class="Bar"/>
    </set>
</class>


<class name="Bar">
    ...
    <property name="localIdentifier" column="local_identifier"/>
    <many-to-one name="parent" column="parent_id" />
</class>

У меня также есть уникальное ограничение на 2 столбца: local_identifier и parent_id (не уникальное ограничение для каждого, но одно уникальное ограничение, содержащее оба, например, не допускаются 2 строки с одинаковым родителем и одинаковым localIdentifier)

alter table bar add constraint unique_bar unique (parent_id, local_identifier)

И этот код, который их использует:

//foo is persistent, foo id = 1
Bars bars = foo.getBars();
bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"]
Bar newBar = new Bar();
newBar.setParent(foo);
newBar.setLocalIdentifier("a");
bars.add(newBar);

Теперь, по какой-то причине, Hibernate не выполняет вещи в порядке их вызова. Он не выполняет clear() (удаление) перед add() (вставка), а наоборот, сначала пытается вставить, получая ConstraintViolationException

Я знаю, что добавление небольшого числа session.flush() после bars.clear(); может исправить это, но в этом случае у меня нет доступа к сеансу неприглядным способом.

Так что, флеш - единственное решение? или есть версия Hibernate, которая соблюдает порядок действий?

Обновление: Кстати, разыменование коллекции приведет к HibernateException от https://www.hibernate.org/117.html#A3:

Я получаю HibernateException: не разыменовывать коллекцию с cascade = "all-delete-orphan" Это произойдет, если вы загрузите объект с каскад = "все-удалить-сирота" коллекция, а затем удалить ссылка на коллекцию. не замени эту коллекцию, используй clear () поэтому алгоритм удаления сирот может обнаружить ваши изменения.

Ответы [ 3 ]

8 голосов
/ 14 января 2010

Я думаю, что нет альтернативы промывке

С здесь :

Hibernate нарушает уникальное ограничение!

Hibernate не совсем так умный с уникальными ограничениями, как это с внешними ключами. Иногда вы возможно, нужно дать небольшую подсказку.

Уникальное нарушение ограничения может происходят, если два объекта оба обновляется, один «освобождает» значение а другой "получает" то же самое значение. Обходной путь должен flush () сеанс вручную после обновления первый объект и перед обновлением второй.

(Такая проблема возникает редко в практика.)
1 голос
/ 20 января 2010

Если вы используете oracle, вы также можете использовать отложенные ограничения, чтобы отложить проверку ограничений до момента фиксации транзакции. Не уверен, если / как это поддерживается другими базами данных.

1 голос
/ 14 января 2010

Если вы хотите избежать сброса сессии, попробуйте заменить весь список (new List<Bar>() вместо Clear()). Hibernate должен фактически удалить все элементы за один выстрел, прежде чем добавлять новые. Просто попробуйте, не уверен, что это работает.

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