将删除孤儿与 where 条件相结合

发布于 2024-09-13 23:40:46 字数 808 浏览 0 评论 0原文

Hibernate 映射问题的行为不明确和/或危险。我有一个一对多关系,它具有级联删除孤立条件和限制集合中项目的 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>

现在假设我有一个与一个或多个 Email 对象关联的 User 对象,其中至少一个对象的 deleted 属性具有“true”值。当我对 User 对象调用 session.delete() 时,会发生以下哪一种情况?

  1. User 和所有Email 对象(包括deleted=true 的对象)均被删除
  2. User 和Email 对象被删除!=null 时被删除。

一方面,场景 1) 忽略了 where 条件,根据领域模型,这可能不正确。但在场景 2) 中,如果父表被删除,并且子表(电子邮件)的连接键存在外键约束,则删除命令将失败。会发生什么情况以及为什么?这是否只是 Hibernate 功能模糊性的另一个例子?

Hibernate mapping question where the behavior is ambiguous and/or dangerous. I have a one-to-many relationship that has a cascade-delete-orphan condition AND a where condition to limit the items in the collection. Mapping here -

<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>

Now suppose that that I have a User object which is associated to one or more Email objects, at least one of which has a 'true' value for the deleted property. Which of the following two will happen when I call session.delete() on the User object?

  1. The User and all the Email objects, including those with deleted=true, are deleted
  2. The User and the Email objects that are deleted!=null are deleted.

On one hand, scenario 1) ignores the where condition, which may not be correct according to the domain model. BUT in scenario 2) if the parent is deleted, and there's a foreign key constraint on the child (email) table's join key, then the delete command will fail. Which happens and why? Is this just another example of how Hibernate's features can be ambiguous?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱人如己 2024-09-20 23:40:46

我没有测试映射,但在我看来,正确的(默认)行为应该是忽略 where 条件并删除所有子记录(这是避免 FK 约束违规的唯一选择删除父级)。从商业角度来看,这可能不“正确”,但另一个选项也不“正确”,因为它不起作用。

总而言之,映射本身看起来不连贯。您应该级联删除操作(并手动处理子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 注释的软删除的启发。虽然没有测试过。

参考文献

I didn't test the mapping but in my opinion, the correct (default) behavior should be to ignore the where condition and to delete all the child records (that's the only option to avoid FK constraints violations when deleting the parent). That's maybe not "correct" from a business point of view but the other option is not "correct" either as it just doesn't work.

To sum up, the mapping itself looks incoherent. You should either not cascade the delete operation (and handle the deletion of the child Email manually).

Or, and I think that this might be the most correct behavior, you should implement a soft delete of both the User and associated Email. Something like this:

<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>

What is done here:

  • We override the default delete using sql-delete to update a flag instead of a real delete (the soft delete).
  • We filter the entities and the association(s) using the where to only fetch entities that haven't been soft deleted.

This is inspired by Soft deletes using Hibernate annotations. Not tested though.

References

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文