我一直在尝试掌握 Hibernate 的逆属性,它似乎只是概念上困难的事情之一。

我得到的要点是,当你有一个父实体(例如Parent) 拥有一组 Child 对象,使用 一对多 映射,在映射上设置 inverse=true 告诉 Hibernate “另一端(子进程)有责任更新自身以维护其表中的外键引用”。

在将子项添加到代码中的集合中,然后保存父级(设置了级联所有)时,这样做似乎有两个好处: 您在数据库上保存了不必要的点击 (因为没有逆集,Hibernate认为它有两个地方可以更新FK关系),并且根据官方文档:

如果协会的列未声明为null,则NHIBERNATE在创建或更新关联时可能会造成约束违规。为了防止此问题,您必须使用标记为逆=“ true”的许多有价值的端(集合或袋子)的双向关联。

到目前为止,这一切似乎都有道理。我不明白的是:你什么时候会 不是 想要在一对多关系上使用 inverse=true 吗?

有帮助吗?

解决方案

由于马修说,你不会想设置逆的唯一情况=真正的是它没有意义的,为孩子负责更新自身,比如在孩子毫不知情的情况下其父。

允许尝试一个现实世界中,而不是在所有人为的例子:

<class name="SpyMaster" table="SpyMaster" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
  <set name="Spies" table="Spy" cascade="save-update">
    <key column="SpyMasterId"/>
    <one-to-many class="Spy"/>
  </set>
</class>

<class name="Spy" table="Spy" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
</class>

间谍首脑可以有间谍,但间谍从来不知道自己的王牌间谍是谁,因为我们还没有列入间谍类多到一的关系。同时,(方便)间谍可能会变成流氓,因此并不需要与是间谍有关。我们可以创建实体如下:

var sm = new SpyMaster
{
    Name = "Head of Operation Treadstone"
};
sm.Spies.Add(new Spy
{
    Name = "Bourne",
    //SpyMaster = sm // Can't do this
});
session.Save(sm);

在这种情况下,你会设置FK列是空,因为节省了SM的行为会插入王牌间谍表和间谍表,只有经过它将然后更新间谍表设置FK。在这种情况下,如果我们设置逆= true,则FK永远不会被更新。

其他提示

尽管有高票接受的答案,但我对此还有另一个答案。

考虑具有以下关系的类图:

Parent => list of Items
Item => Parent

没有人 曾经 也就是说,Item => Parent 关系对于 Parent => Items 关系来说是多余的。一个项目可以引用任何父项。

但在你的应用程序中, 你知道这些关系是多余的. 。您知道关系不需要单独存储在数据库中。所以你决定将它存储在 单个外键, ,从 Item 指向 Parent。这个最少的信息足以构建列表 参考回来。

要将其与 NH 进行映射,您需要做的就是:

  • 对两个关系使用相同的外键
  • 告诉 NH 其中一个(列表)对另一个来说是多余的,并且在存储对象时可以忽略。(这就是 NH 实际上所做的 inverse="true")

这些是与逆相关的想法。没有其他的。这不是一种选择,只有一种正确的映射方法。


间谍问题:这是一个完全不同的讨论 如果 您想要支持从 Item 到 Parent 的引用。这取决于你的商业模式,NH 对此不做任何决定。如果其中一个关系缺失,当然就没有冗余,也没有使用逆。

滥用: 如果您在内存中没有任何冗余的列表上使用 inverse="true" ,则它不会被存储。如果您没有指定 inverse="true" (如果应该存在的话),NH 可能会存储冗余信息两次。

如果你想有一个单向关联,即孩子们不能定位到父。如果是这样,你FK列应为空,因为孩子会在父母面前被保存。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top