【问题标题】:NHibernate Interceptor clarification (on deletion/ dirty)NHibernate 拦截器澄清(删除/脏)
【发布时间】:2012-04-23 11:46:22
【问题描述】:

我可能正在尝试一些(坏的),只是想看看我想出了什么。 对于初学者,我们以 DDD 方式构建了一个应用程序——我们的意见。该设计是“经典” DDD,这意味着我们有聚合根的存储库。 我们确实有一个基本实体,我们在其中覆盖 Equals、GetHashCode 等。我们的实体只是逻辑删除,即我们使用 IsActive 字段。 作为 ORM,我们使用 NHibernate >3。

我想尝试的事情:我希望能够使用如下语法从聚合根内的列表中删除一个实体:

aggregateRoot.Entities.Remove(entity);

在持久层中,“entity”的默认 NHibernate 行为(“entity”具有对“aggregateRoot”的反向引用)是在“aggregateRoot”列上使用 NULL 更新“entity”。我们真正想做的是:

repository.Delete(entity);

它只是将“entity”标记为非活动状态,而“entity”仍保留在“aggregateRoot”的集合中。

很可能我的想法很愚蠢(正如我再次说过的那样),但我想尝试教 NHibernate 不应该使用对“aggregateRoot”的空引用来更新“实体”,只需使其处于非活动状态.为什么?因为我想在需要的地方明确使用存储库。

我要问的是这是否可以通过 NHibernate 拦截器实现;我还没有尝试过它们,我想优先考虑我的积压。

【问题讨论】:

  • “只是让它处于非活动状态。为什么?因为我想在需要的地方明确使用存储库。” =>我不明白。明确地使用存储库来做什么?你真的想用那个实体做什么?禁用还是删除?
  • 我想禁用该实体。我希望域不知道禁用的实体。企业不知道当我删除实体时,我只是禁用它们。

标签: nhibernate domain-driven-design ddd-repositories


【解决方案1】:

您为什么不在实体上实现一个 Delete 方法?您可以将其隐藏在核心界面后面。优点是完全不了解持久性的实现,不需要 NH 存在。

class Root
{
  // ...
  public void Remove(Entity entity)
  {
    IRootManaged managed = (IRootManaged)entity
    managed.Delete();
  }
}

class Entity : IRootManaged
{
  // ...
  public bool IsDeleted { get; private set; }

  public void IRootManaged.Delete()
  {
    this.IsDeleted = true;
  }
}

对不起,如果我错过了这里的重点......

【讨论】:

  • 感谢您的回答。这是我的cmets: 1. 为什么实体应该知道如何删除自己?毕竟,实体的创建和持久化(包括删除)不是业务模型的核心部分,所以它们应该被排除在领域模型之外;实体创建应该由工厂(它的一种风格)或构建器或原型管理,你明白了;实体删除由存储库管理,取决于 DDD 风格(洋葱与否)与业务层、工厂、(至少某些)规范处于同一级别。
  • 因为“当 'entity' 保留在 'aggregateRoot 的集合中时处于非活动状态”不会被删除。它只是“标记为非活动”。该实体不知道它是如何被删除的。但它绝对可以知道它是如何设置为“非活动”的。删除更物理,不应该在实体中实现。
  • 2.我问是否有可能在选择的持久层(这里是 NH)中截取“嘿,他从集合中拉出那个实体,让我删除引用”的调用并覆盖它,这样他就会表现得像“嘿,他从集合中取出了那个实体,所以我们把它标记为已删除。”
  • 我实际上无法关注这里。我不明白这部分:“默认的 NHibernate 行为是在 'aggregateRoot' 列上使用 NULL 更新 'entity'”。 NH 从不更新实体中的任何内容。什么是“从收藏中拉出来”?什么是“删除参考”?您可以为您的问题添加一些映射和一些代码。
  • 所以我猜你将它映射为逆一对多。如果要将其保留在集合中,为什么要将其从集合中删除?如果代码做的事情完全不同于它看起来做的事情,它就不会为自己说话。如果要将其保留在集合中并将其标记为已删除,则代码应如下所示。 IMO,其他一切都是信息隐藏。您会看到,了解实体是否被实际删除至关重要。
【解决方案2】:

在经典的 DDD 中,aggregateRoot.Entities.Remove(entity); 无论如何都是不好的做法。您最好在根实体上创建一个方法,例如 RemoveEntity(Entity e),然后您将封装 Delete 机制,您将在其中将 Entity.IsActive 设置为 false。

【讨论】:

  • 我确实有一个方法 RemoveEntity(Entity entity);在它的实现中,我做了上面的事情,aggregateRoot.Entities.Remove(entity)。那是来自 aggregateRoot 域对象的代码,而不是来自业务层的代码。
  • 为什么我不在实体中做 IsActive = false?因为我相信那不是它的位置。在我看来,这与持久性有关。非活动实体将在带外被激活,而不是业务场景的一部分。因此,如果它不是商业行为,则不应在代码中表示。
  • 假设你已经设法做你想做的事,并且你让实体 E1 在数据库中处于非活动状态,你将如何从 AR1.Entities 中过滤掉 E1 来获取 AR1?
  • 您的意思是我将如何忽略附加到聚合根的非活动实体。我想到了两种可能性:1)您从存储库中手动加载它们; 2)您在树上运行规范。
  • 但是你自己也这么说——在你看来,它与持久性有关(我倾向于不同意你的观点),因此选项 2 是不可接受的。我认为它与持久性无关,并且选项 2 是可以接受的,如果是这样,您不必首先从集合中删除实体,因为您会使用规范。
【解决方案3】:

【讨论】:

  • 是的,我知道 Ayende 写了什么。我读了他的博客,我发现它们有时在特定情况下是正确的。我相信这不是我们的背景。我们不删除不是因为我们要审核(可能不在计划中);想象一下,目前我们的应用程序中没有回收站;这并不意味着在(不久的)将来不会有任何东西。如果您担心查询时间,我们可以对实体的业务键和 IsActive 列进行索引并完成。
猜你喜欢
  • 2017-11-10
  • 1970-01-01
  • 2019-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-08
  • 1970-01-01
  • 2015-12-20
相关资源
最近更新 更多