何时在NHibernate / Hibernate的OneToMany关系中使用inverse=false?

70

我一直在努力理解Hibernate的inverse属性,但它似乎是那种概念上比较困难的东西。

我的理解是,当您有一个父实体(例如Parent),该实体使用一对多映射拥有Child对象集合时,将映射上的inverse=true设置告诉Hibernate,“另一侧(Child)有责任更新自身以维护其表中的外键引用”。

这样做似乎在您的代码中向集合添加Children,然后保存Parent(同时设置cascade-all)时有两个好处:您可以节省数据库中不必要的请求(因为如果没有设置inverse,Hibernate认为有两个地方需要更新FK关系),并且根据官方文档:

如果关联的列被声明为NOT NULL,则NHibernate在创建或更新关联时可能会导致约束冲突。为了防止这种问题,您必须使用双向关联,并将具有多个值的端(set或bag)标记为inverse=“true”。

到目前为止,这一切都似乎很有道理。我不明白的是:在什么情况下您不想在一对多关系上使用inverse=true?

3个回答

82

正如Matthieu所说,你不想设置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的操作会插入SpyMaster表和Spy表,仅在此之后才会更新Spy表以设置FK。在这种情况下,如果我们设置inverse = true,则FK将永远不会得到更新。

这对我没用。它从不运行更新,只插入它们。 - BradLaney

29
尽管最高票答案被接受,但我有另外一个解答。
考虑一个带有以下关系的类图:
父类 => 项目列表 项目 => 父类
没有人曾经说过,项目=>父类关系对于父类=>项目关系是多余的。一个项目可以引用任何父类。
但是在您的应用程序中,您知道这些关系是冗余的。您知道不需要在数据库中单独存储这些关系。因此,您决定将其存储在一个单一的外键中,从项目指向父类。这个最小信息足以建立列表和引用回去。
您需要做的就是在NH中映射它:
- 对于两个关系都使用相同的外键 - 告诉NH其中一个(列表)是冗余的,可以在存储对象时忽略另一个。(这就是NH实际上使用inverse="true"所做的)
这些是与inverse有关的相关想法。没有其他选择,只有一种正确的映射方式。
间谍问题: 如果要支持从项目到父类的引用,则完全是另一回事,并非此处讨论范围。这取决于您的业务模型,NH不会做出任何决定。如果其中一个关系缺失,则当然没有冗余信息,也没有使用inverse的必要。
误用: 如果在内存中没有冗余的列表上使用inverse="true",它就不会被存储。如果应该有但未指定inverse="true",则NH可能会将冗余信息存储两次。

我发现那个答案比被采纳的答案更易于理解。 - r3try
比起我的回答(https://dev59.com/dG025IYBdhLWcg3wKCf-#6951546)来说简单明了得多。 - Daniel Schilling

15
如果你想要一个单向关联,也就是子项不能导航到父项。如果是这样的话,你的FK列应该是可空的,因为子项将在父项之前保存。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接