【问题标题】:Nhibernate doesn't set Id when adding Entity to a list with DefaultCascade.All()使用 DefaultCascade.All() 将实体添加到列表时,Nhibernate 不设置 Id
【发布时间】:2011-08-07 12:50:44
【问题描述】:

使用 ASP.net MVC 我正在这样做:

[HttpPost]
[TransactionFilter]
public ActionResult Create(User user)
{
    // Ommited some things for the sake of brevity
    _userRepository.Add(user);
    return RedirectToAction("Details", new { Id = user.Id });
}

这按我的预期工作。现在我正在尝试这样做:

[HttpPost]
[TransactionFilter]
public ActionResult Create(User user, ChildOfUser userChild)
{
    // Ommited some things for the sake of brevity
    var parent = _userRepository.GetById(user.Id);
    parent.Children.Add(userChild);

    return RedirectToAction("Details", new { Id = userChild.Id });
}

这会失败,因为 userChild.Id 为空。第一种情况有效,因为在 repo 中我调用了session.Save(user);,并且此调用将更改 user.Id 属性。

(User)parent.Children.Add(userChild); 调用不会更改 userChild.Id 属性。只有在调用transaction.Commit(); 之后,userChild.Id 才会有一个有意义的值。虽然我希望通过将 userChild 添加到集合中来设置 Id。

现在,NHibernate 应该处理这个吗?还是我的期望错了?如果有办法让 NHibernate 处理这个问题,那就太棒了。

编辑 在这种情况下,ID 始终是 GUID。我可以自己设置它们(它们是全局唯一的权利...),NHibernate 会像它自己生成 Id 一样使用它吗?

【问题讨论】:

  • 重新编辑:是的,NHibernate 将使用它,并且客户端生成的 Id(例如 GUID 或 HiLo)对您的 ORM 性能友好,因此对您的应用程序也是如此。当您使用预生成的 id 时,将不再需要获取父 ID 的 db 往返;对您的表的争用也较少,生成后的 Id 往往会锁定表,每个 Id 请求者都需要等待 Id 生成,特别是如果表包含在事务中。

标签: c# nhibernate domain-driven-design


【解决方案1】:

parent.Children.Add(userChild); 与 NHibernate 无关,它们是内存中的操作,实际上它们是 .NET 基础库的一部分,早在有人将 Hibernate 移植到 .NET 之前。 collection.Add 不是 NHibernate 操作

仅在调用 transaction.Commit(); 之后userChild.Id 将有一个 有意义的价值。虽然我希望通过添加来设置 Id userChild 到集合中。

您观察到的是正确的,NHibernate 对您的对象的作用只有在您调用 Save/Commit 时才会发挥作用。

【讨论】:

  • 理论上,NHibernate 可以代理集合,并在 Add 时调用 session.Save(item)(启用 Cascade 时)。否则,这意味着我必须使用 userChild 存储库进行删除。这不符合 DDD 的聚合根原则(只有聚合根有 repo):s
  • 您可以从聚合根目录中删除,NHibernate 也可以愉快地删除其子实体。
  • 我的错,我的意思是“添加/保存”,我说的是“删除”。
  • 如果您的映射正确,您应该能够将子对象添加到父对象的集合中,然后保存父对象。这也应该将孩子推回数据库。它看起来像这样: parent.Children.Add(userChild); _userRepository.Save(父);
  • @AndyM 听起来确实很有趣并且可以解决我的问题,但它对我不起作用。你确定userChild.Id会在调用transaction.Commit()之前设置吗?
【解决方案2】:

现在,NHibernate 应该处理这个吗?

不,这是由于Unit of Work 模式。工作单元模式背后的一条推理是实用的,它与减少事务和数据库往返次数有关。使用工作单元模式的另一个原因是它与业务意义上的工作单元保持一致——工作单元定义了业务域中操作的边界。由于 NHibernate 不知道业务域的性质,因此工作单元的声明被委托给客户端。此外,将工作单元声明委托给持久层之外通常是有利的。有关示例,请参阅this 问题。

【讨论】:

    【解决方案3】:

    在使用 .Add() 之后,我通过使用 ISession.Flush() 方法解决了这个特殊问题

    不过,我不推荐这种做法。现在,我立即在实体构造函数中设置了 Guid Id。这让 MVC 和 NHibernate 都很高兴。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多