何时在NHibernate / Hibernate OneToMany关系上使用inverse = false?
我一直在努力去理解Hibernate的inverse属性,而这似乎只是那些概念上困难的事情之一。
我得到的要点是当你有一个使用一对多映射的具有Child对象集合的父实体(例如Parent)时,在映射上设置inverse = true会告诉Hibernate“对方)有责任自行更新以维护其表中的外键引用。
这样做似乎有两个好处,当涉及到代码中的集合添加孩子,然后保存父级(级联所有设置): 你保存一个不必要的命中数据库 (因为没有反设置,Hibernate认为它有两个地方更新FK关系),并根据官方文件:
如果关联的列被声明为NOT NULL,那么NHibernate在创build或更新关联时可能会导致约束违规。 为了防止这个问题,你必须使用与被标记为inverse =“true”的许多有价值的结尾(集合或行李)的双向关联。
这一切似乎到目前为止是有道理的。 我不明白的是:什么时候你不想在一对多的关系上使用inverse = true?
正如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>
间谍pipe理员可以有间谍,但是间谍们不知道他们的间谍pipe理员是谁,因为我们没有在间谍课堂中包含多对一的关系。 另外(方便)间谍可能变成stream氓,所以不需要与间谍大师相关联。 我们可以创build如下的实体:
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表和间谍表中,只有在那之后它才会更新间谍表来设置FK。 在这种情况下,如果我们设置inverse = true,那么FK永远不会被更新。
尽pipe接受了高票接受的答复,但我还有另一个答案。
考虑这些关系的类图:
父项=>项目列表 Item =>父项
没有人说,Item => Parent关系对于Parent => Items关系是多余的。 一个Item可以引用任何Parent。
但是在你的申请中, 你知道这种关系是多余的 。 你知道关系不需要单独存储在数据库中。 所以你决定把它存储在一个单独的外键中 ,从Item指向Parent。 这个最小的信息足以build立清单和参考。
所有你需要做的与NH地图这是:
- 两个关系使用相同的外键
- 告诉NH,一个(列表)对另一个是多余的,在存储对象时可以忽略。 (NH实际上是用
inverse="true"
)
这些是与逆相关的思想。 没有其他的。 这不是一个select,只有一种正确的映射方式。
间谍问题 : 如果你想支持从项目到父项的引用,这是一个完全不同的讨论。 这取决于您的商业模式,NH在此不做任何决定。 如果其中一个关系丢失,当然没有冗余,也没有使用逆。
误用:如果在内存中没有任何冗余的列表上使用inverse =“true”,它就不会被存储。 如果你不指定inverse =“true”,那么NH可以存储冗余信息两次。
如果你想有一个单向的关联,即孩子们不能导航到父。 如果是这样的话,那么你的FK列应该是NULLABLE的,因为孩子会被保存在父代之前。