【问题标题】:Removal of child from aggregate root and database persistence从聚合根和数据库持久性中删除子项
【发布时间】:2014-05-22 08:04:22
【问题描述】:

(这可能是重复的,但我在阅读的其他问题中没有找到任何令人满意的答案。)

我需要一些关于如何将聚合根的子实体的删除传播到数据库层的指导。我已经/阅读了几种不同的处理方法:

  1. 将已删除的子项保留在单独的集合中。让存储库在保存时删除集合中的所有项目。

  2. 直接调用某种数据映射层或存储库。

  3. 执行存储库/UoW 可能提供/侦听的某种类型的委托/事件。

  4. 什么都不做。让工作单元或存储库将整个聚合根与“非脏”副本进行比较。

值得注意的是,我真正的聚合根实现包含多个可能被删除的子集合。

为了清楚起见,这里是一个简单的例子:

public class AggregateRoot 
{
    private List<ChildEntity> _children;
    public IEnumerable<ChildEntity> Children 
    { 
        get 
        { 
            return _children; 
        } 
    }
    public void RemoveChild(ChildEntity child)
    {
        _children.Remove(child);

        // What to do here?

        // Option 1: Keep removed children i separate collection. Let 
        // the repository remove them on save.
        RemovedChildren.Add(child);

        // Option 2: Call some kind of data mapping layer or repository directly
        _childRepository.Delete(child);

        // Option 3: Execute some type of delegate/event that a repository 
        // may provide/listen to.
        _onChildRemoved(this, child);

        // Option 4: Do nothing. Let the Unit of work or repository compare 
        // the whole aggregate root with a "non-dirty" copy.

    }
}

我认为选项 1 和 2 不是很优雅。

选项 4 很好,因为我不必在聚合根中实现任何逻辑,但由于我的实际实现非常大,我必须比较很多属性和集合。

我倾向于选择选项 3。它的问题是它可能需要大量的委托/事件。也许我可以实现一个通用的委托/事件。

这一定是一个相当普遍的问题,但我看到的这方面的例子非常少。你会如何处理这个问题?

【问题讨论】:

  • 如果你有一个工作单元,你可能有一个在 UoW 生命周期范围内的存储库。在存储库中记录删除(它应该在哪里)并且在提交 UoW 时,存储库可以查看其删除的项目并根据需要从底层源中删除它们。如果这类似于 EF,那么它会为您处理。
  • @AdamHouldsworth 那么您将如何通知存储库删除? (顺便说一下,我没有使用EF)
  • 当您删除项目时,您可以引发领域事件,以便环境变化跟踪可以捕获它以供以后参考,或者您可以在您的领域模型本身中推广这个想法(可以删除项目并所以不可用)。

标签: c# domain-driven-design aggregateroot


【解决方案1】:

选项 1: 我想在您的业务中没有 RemovedChildren 这样的概念,因此我认为聚合不应该包含这样的集合。请注意,有时可能会有 ChildrenHistory、HistoricalChildren 等概念

选项 2: 我读过很多次聚合不应该使用存储库,聚合不应该注入任何服务。但是,您可以使用双重调度模式并提供方法签名,例如:

public void RemoveChild(ChildEntity child, IChildRepository repository)
{
    // check conditions, business logic etc
    // remove using repository

但是它强制调用者提供在某些情况下可能难以实现的存储库

选项 3: 我以前没有为此目的使用事件。但这对我来说似乎还不错。您可以使用事件总线将实体删除通知感兴趣的存储库。

选项 4: 我认为这是最好的方法,UoW 应该处理项目删除。您可以通过在实体上设置某种标志或将它们的 ParentId 设置为 0(这就是 EF 在幕后所做的)来将您的实体标记为已删除。提交时,您可以检查加载到内存中的所有对象并删除那些标记为删除的对象。这迫使我们在域层编写最少的基础设施代码,但是我们需要在 UoW 中编写额外的代码来删除孤儿。

【讨论】:

  • 感谢您的回答拓宽了我对这个问题的看法。我实际上选择了选项 3,让聚合根的存储库删除任何子实体,因为没有为子实体实现存储库。下次我可能会选择选项 4,但它似乎需要在 UoW 中更通用地实现实体删除。一个选项可能是选项 3 和 4 的组合 - 引发 UoW 监听的事件...
猜你喜欢
  • 1970-01-01
  • 2014-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 2017-10-29
相关资源
最近更新 更多