Объединение delete-orphan с условием where - PullRequest
5 голосов
/ 13 августа 2010

Вопрос о спящем отображении, где поведение неоднозначно и / или опасно. У меня есть отношение один ко многим, у которого есть условие 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?

  1. Пользователь и все объекты электронной почты, включая объекты с удаленным = true, удаляются
  2. Объекты User и Email, которые были удалены! = Null, удаляются.

С одной стороны, сценарий 1) игнорирует условие where, которое может быть неправильным в соответствии с моделью предметной области. НО в сценарии 2) если родитель удаляется, и существует ограничение внешнего ключа на ключ соединения дочерней (электронной) таблицы, то команда удаления завершится неудачно. Что происходит и почему? Это просто еще один пример того, как функции Hibernate могут быть неоднозначными?

1 Ответ

4 голосов
/ 13 августа 2010

Я не тестировал сопоставление, но, по моему мнению, правильное (по умолчанию) поведение должно заключаться в игнорировании условия 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, чтобы выбирать только те объекты, которые не были удалены мягко.

Это вдохновлено Софт удаляется с использованием аннотаций Hibernate .Не проверено, однако.

Ссылки

...