Сочетание delete-orphan с условием where
Вопрос о спящем отображении, где поведение неоднозначно и / или опасно. У меня есть отношение один ко многим, у которого есть условие cascade-delete-orphan И условие where для ограничения элементов в коллекции. Картирование здесь -
<hibernate-mapping>
<class name="User" table="user" >
<!-- properties and id ... -->
<set table="email" inverse="true" cascade="all,delete-orphan" where="deleted!=true">
<key column="user_id">
<one-to-many class="Email"/>
</set>
</class>
</hibernate-mapping>
Теперь предположим, что у меня есть объект User, который связан с одним или несколькими объектами электронной почты, по крайней мере один из которых имеет значение "true" для удаленного свойства. Что из следующих двух произойдет, когда я вызову session.delete() для объекта User?
- Пользователь и все объекты электронной почты, включая объекты с удаленным =true, удаляются
- Пользователь и объекты электронной почты, которые удаляются!= Null, удаляются.
С одной стороны, сценарий 1) игнорирует условие where, которое может быть неправильным в соответствии с моделью предметной области. НО в сценарии 2) если родитель удаляется и существует ограничение внешнего ключа на ключ соединения дочерней (электронной) таблицы, то команда удаления завершится неудачно. Что происходит и почему? Это просто еще один пример того, как функции Hibernate могут быть неоднозначными?
1 ответ
Я не тестировал отображение, но, по моему мнению, правильное (по умолчанию) поведение должно заключаться в игнорировании where
и удалить все дочерние записи (это единственный способ избежать нарушения ограничений FK при удалении родительского элемента). Возможно, это не "правильно" с точки зрения бизнеса, но другой вариант не является "правильным", так как он просто не работает.
Подводя итог, само отображение выглядит несвязным. Вы не должны каскадировать delete
операция (и обработать удаление ребенка Email
вручную).
Или, и я думаю, что это может быть наиболее правильным поведением, вы должны реализовать мягкое удаление обоих User
и связанные Email
, Что-то вроде этого:
<hibernate-mapping>
<class name="User" table="user" where="deleted<>'1'">
<!-- properties and id ... -->
<set table="email" inverse="true" cascade="all,delete-orphan" where="deleted<>'1'">
<key column="user_id">
<one-to-many class="Email"/>
</set>
<sql-delete>UPDATE user SET deleted = '1' WHERE id = ?</sql-delete>
</class>
<class name="Email" table="email" where="deleted<>'1'">
<!-- properties and id ... -->
<sql-delete>UPDATE email SET deleted = '1' WHERE id = ?</sql-delete>
</class>
</hibernate-mapping>
Что здесь сделано:
- Мы перезаписываем удаление по умолчанию, используя
sql-delete
обновить флаг вместо реального удаления (мягкое удаление). - Мы фильтруем объекты и ассоциации, используя
where
выбирать только те объекты, которые не были удалены мягко.
Это связано с удалением Soft с использованием аннотаций Hibernate. Не проверено, хотя.