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

Jam*_*len 70 collections nhibernate hibernate inverse one-to-many

我一直试图掌握Hibernate的逆属性,它似乎只是概念上难以解决的问题之一.

我得到的要点是,当你有一个使用一对多映射的Child对象集合的父实体(例如Parent)时,在映射上设置inverse = true告诉Hibernate'另一边(Child) )有责任更新自己以维护其表中的外键引用'.

这样做对于在代码中向集合中添加Children,然后保存Parent(使用cascade-all set)有两个好处:在数据库上保存一个不必要的命中(因为没有逆集,Hibernate认为它有两个地方更新FK关系),并根据官方文档:

如果关联的列被声明为NOT NULL,则NHibernate在创建或更新关联时可能会导致约束违规.要防止出现此问题,必须使用标记为inverse ="true"的多值结束(集合或包)的双向关联.

到目前为止,这一切似乎都有意义.我不明白是这样的:你什么时候会希望使用逆=真正在一个一对多的关系?

Nig*_*gel 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>
Run Code Online (Sandbox Code Playgroud)

间谍可以有间谍,但间谍从来不知道他们的间谍是谁,因为我们没有在间谍班中包含多对一的关系.另外(方便地)间谍可能会变成流氓,所以不需要与间谍大师联系.我们可以创建如下实体:

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);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您可以将FK列设置为可为空,因为保存sm的行为将插入到SpyMaster表和Spy表中,然后才会更新Spy表以设置FK.在这种情况下,如果我们设置inverse = true,则FK永远不会更新.


Ste*_*ger 29

尽管有高投票的答案,我还有另一个答案.

考虑具有这些关系的类图:

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可以存储两次冗余信息.


Mat*_*uGD 15

如果您想要单向关联,即孩子无法导航到父级.如果是这样,您的FK列应为NULLABLE,因为子项将保存在父项之前.