【问题标题】:When to use inverse=false on NHibernate / Hibernate OneToMany relationships?何时在 NHibernate / Hibernate OneToMany 关系上使用 inverse=false?
【发布时间】:2009-06-30 00:06:27
【问题描述】:
我一直在尝试掌握 Hibernate 的逆属性,它似乎只是概念上困难的事情之一。
我得到的要点是,当您有一个父实体(例如 Parent),该实体具有使用 一对多 映射的子对象集合时,在映射上设置 inverse=true告诉 Hibernate '另一方(孩子)有责任更新自己以维护其表中的外键引用'。
在代码中将子项添加到集合中,然后保存父项(设置了 cascade-all)时,这样做似乎有 2 个好处:you save an unneccessary hit on the database(因为没有反向设置,Hibernate 认为它有两个更新FK关系的地方),并根据官方文档:
如果一个列
关联被声明
NOT NULL,NHibernate 可能会导致
创建时违反约束
或更新关联。阻止
这个问题,你必须使用
双向关联
许多有价值的末端(套装或袋子)
标记为 inverse="true"。
到目前为止,这一切似乎都说得通。我不明白的是:您什么时候不想在一对多关系上使用 inverse=true?
【问题讨论】:
标签:
nhibernate
hibernate
collections
one-to-many
inverse
【解决方案1】:
正如 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 将永远不会更新。
【解决方案2】:
尽管被高票接受的答案,我有另一个答案。
考虑具有这些关系的类图:
父级 => 项目列表
项目 => 父级
没有人曾经说过,Item => Parent 关系对于 Parent => Items 关系是多余的。一个 Item 可以引用任何 Parent。
但在您的应用程序中,您知道这些关系是多余的。您知道关系不需要单独存储在数据库中。因此,您决定将其存储在一个单个外键中,从 Item 指向 Parent。这些最少的信息足以构建列表和返回的引用。
用 NH 映射它所需要做的就是:
- 对两个关系使用相同的外键
- 告诉 NH 一个(列表)对于另一个来说是多余的,并且在存储对象时可以被忽略。 (这就是 NH 对
inverse="true" 所做的实际操作)
这些是与逆相关的想法。没有其他的。这不是一种选择,只有一种正确映射的方式。
间谍问题:
这是一个完全不同的讨论如果你想支持从 Item 到 Parent 的引用。这取决于您的商业模式,NH 不会对此做出任何决定。如果缺少其中一个关系,当然没有冗余,也没有使用逆。
误用:如果您在内存中没有任何冗余的列表上使用 inverse="true",它就不会被存储。如果你没有指定 inverse="true" 如果它应该在那里,NH 可能会存储两次冗余信息。
【解决方案3】:
如果你想有一个单向关联,即孩子不能导航到父。如果是这样,您的 FK 列应该为 NULLABLE,因为子级将在父级之前保存。