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

发布于 2024-07-26 14:16:36 字数 667 浏览 3 评论 0原文

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

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

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

如果a列 宣布关联 NOT NULL,NHibernate 可能会导致 创建时违反约束 或更新关联。 阻止 这个问题,你必须使用 与 的双向关联 许多有价值的末端(套装或包) 标记为 inverse="true"。

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

I have been trying to get to grips with Hibernate's inverse attribute, and it seems to be just one of those things that is conceptually difficult.

The gist that I get is that when you have a parent entity (e.g. Parent) that has a collection of Child objects using a one-to-many mapping, setting inverse=true on the mapping tells Hibernate that 'the other side (the Child) has responsibility to update itself to maintain the foreign key reference in its table'.

Doing this appears to have 2 benefits when it comes to adding Children to the collection in your code, and then saving the Parent (with cascade-all set): you save an unneccessary hit on the database (because without inverse set, Hibernate thinks it has two places to update the FK relationship), and according to the official docs:

If the column of a
association is declared
NOT NULL, NHibernate may cause
constraint violations when it creates
or updates the association. To prevent
this problem, you must use a
bidirectional association with the
many valued end (the set or bag)
marked as inverse="true".

This all seems to make sense so far. What I don't get is this: when would you NOT want to use inverse=true on a one-to-many relationship?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

何止钟意 2024-08-02 14:19:07

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

If you want to have an unidirectional association i.e. that the children can't navigate to the Parent. If so, you FK column should be NULLABLE because the children will be saved before the parent.

风吹短裙飘 2024-08-02 14:18:40

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

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

Parent => list of Items
Item => Parent

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

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

要将其映射到 NH,您所需要做的就是:

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

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


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

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

Despite of the high-voted accepted answer, I have another answer to that.

Consider a class diagram with these relations:

Parent => list of Items
Item => Parent

Nobody ever said, that the Item => Parent relation is redundant to the Parent => Items relation. An Item could reference any Parent.

But in your application, you know that the relations are redundant. You know that the relations don't need to be stored separately in the database. So you decide to store it in a single foreign key, pointing from the Item to the Parent. This minimal information is enough to build up the list and the reference back.

All you need to do to map this with NH is:

  • use the same foreign key for both relations
  • tell NH that one (the list) is redundant to the other and could be ignored when storing the object. (That is what NH actually does with inverse="true")

These are the thoughts which are relevant for inverse. Nothing else. It is not a choice, there is only one way of correct mapping.


The Spy Problem:
It is a completely different discussion if you want to support a reference from the Item to the Parent. This is up to your business model, NH doesn't take any decisions in this. If one of the relations is missing, there is of course no redundancy and no use of inverse.

Misuse: If you use inverse="true" on a list which doesn't have any redundancy in memory, it just doesn't get stored. If you don't specify the inverse="true" if it should be there, NH may store the redundant information twice.

A君 2024-08-02 14:18:17

正如 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 将永远不会更新。

As Matthieu says, the only case where you wouldn't want to set inverse = true is where it does not make sense for the child to be responsible for updating itself, such as in the case where the child has no knowledge of its parent.

Lets try a real world, and not at all contrived example:

<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>

Spymasters can have spies, but spies never know who their spymaster is, because we have not included the many-to-one relationship in the spy class. Also (conveniently) a spy may turn rogue and so does not need to be associated with a spymaster. We can create entities as follows:

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);

In such a case you would set the FK column to be nullable because the act of saving sm would insert into the SpyMaster table and the Spy table, and only after that would it then update the Spy table to set the FK. In this case, if we were to set inverse = true, the FK would never get updated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文