NHibernate 搬起石头砸自己的脚:关联所有权和版本控制

NHibernate shoots itself in the foot: Association ownership and versioning

情况

假设:

观察到的行为:

  1. 打开会话和交易。
  2. 通过一些查询加载一些 parent object 及其 child 集合。
  3. 将新创建的 child 添加到 child 集合。
  4. SaveOrUpdate parent.
  5. NHibernate 首先将 child 添加到数据库,给它一个版本。
  6. 然后它会处理 parent 的关联(因为它负责)并更新 child 的外键(谢天谢地它可以为 null...),增加 child 的版本。 但是,它不会更新会话中的 child。
  7. 最后它应用级联并在 child 上调用 AddOrUpdate。唯一的问题:它在会话中有一个过时的版本,导致 ConcurrencyException 被抛出。 NHibernate 搬起石头砸自己的脚。

问题

为什么 NHibernate 在应用更新关联的逻辑时不更新会话中的 child object?其背后的原理是什么?在我看来,使用版本控制对 parent/child 进行建模的唯一合理方法是使用 Inverse(true).

澄清:我对任何变通办法and/or更合适的配置不感兴趣。我知道那些。我只对所描述场景中 NHibernate 行为背后的推理感兴趣。

编辑:主要问题似乎是(imo)NHibernate 本身不能完全控制版本控制。相反,它让数据库来处理它(至少在我的配置中)。不幸的是,这不能很好地结合在一起,因为 NHibernate 在更新关联时不会预期客户端的版本更改,因为从更高级别的角度来看,关联属于 parent 因此没有变化在 child 中是预期的。这至少是它背后的一个可能的理由。

NHibernate is shooting itself in the foot.

这不太可能。你的用例很典型,NH 是一个成熟的框架。您可能发现了一个错误,但更有可能是映射或 object 图的状态在 NH 尝试保留它时出现问题。

Why does NHibernate not update the child objects in the session when it applies the logic to update the association?

我认为这是因为对关联的更改只会影响 parent。如果没有相互引用,从实体的角度来看,child 没有任何变化。

However, it does not update the child in the session.

您期待什么变化? child 现在 link 编辑到 parent,但是这个 link 被建模为 parent 职责的一部分。我想如果 child 持有对其 parent 的引用,这可能会有不同的看法,但你没有说你的问题是否属于这种情况。

#6 粗体部分可能是一个错误,如果你的意思是 children 版本未被检索并设置为最新版本。检查 https://nhibernate.jira.com, and if nothing, eventually report it with a complete test case. At least something like a MCVE。我并不是要重现您的案例,因为您的问题让太多的编码工作取决于谁愿意检查您的场景发生了什么。我什至不知道您使用的是哪种版本控制机制:它们很多,具有不同的行为。
在你的编辑之后,它似乎是一些计数器处理的数据库端。但是如果你希望有人研究你的情况发生了什么,以及这背后是否有充分的理由,或者你这边的错误或者在 NHibernate 方面,或者只是不幸的不受支持的功能与实际使用的技术的组合,MCVE 仍然是必须的:class 定义、映射、使用的数据库、使用的软件版本、经过测试的代码以及实际重现您的问题.)

现在您可以做一些事情:为什么要让 parent 成为 children 的 "responsible"?这与级联无关,您实际上可能只需要级联。如果您的关系是双向的,则可能是这种情况,将 children 映射回它们的 parent。更多 details here.

否则,如果您的关系是 uni-directional,并且不需要支持已分离的 children,您应该将键设置为 non-nullable 并且不要求来自 parent。更多 details here。这将完成 set 的工作,但会产生 list 的问题,例如没有索引更新和列表中出现空洞。