【问题标题】:.NET DDD Domain Pattern with Grandchildren.NET DDD 域模式与孙子
【发布时间】:2018-07-21 21:48:40
【问题描述】:

我想在我的 .NET Core 域模型中实现 DDD 模式。 这是具有聚合子实体和聚合孙实体的聚合根的示例:

public class Supplier
    : Entity, IAggregateRoot
{
    private string _name;

    private readonly List<Catalog> _catalogs;
    public IReadOnlyCollection<Catalog> Catalogs => _catalogs;

    protected Supplier() { _catalogs = new List<Catalog>(); }

    public Supplier(string name)
    {
        _catalogs = new List<Catalog>();
        _name = name;
    }

    public void AddCatalog(string name)
    {
        var catalog = new Catalog(name);
        _catalogs.Add(catalog);
    }

    public void AddCatalogItem(int catalogId, string name)
    {
        var catalogItem = new CatalogItem(name);
        _catalogs.Single(c => c.Id == catalogId).AddCatalogItem(catalogItem);
    }
}

这里是聚合子的代码:

public class Catalog
    : Entity
{
    private string _name;

    private readonly List<CatalogItem> _catalogItems;
    public IReadOnlyCollection<CatalogItem> CatalogItems => _catalogItems;

    protected Catalog() { _catalogItems = new List<CatalogItem>(); }

    public Catalog(string name)
    {
        _catalogItems = new List<CatalogItem>();
        _name = name;
    }

    public void AddCatalogItem(CatalogItem catalogItem)
    {
        _catalogItems.Add(catalogItem);
    }
}

还有总孙:

public class CatalogItem
    : Entity
{
    private string _name;

    protected CatalogItem() { }

    public CatalogItem(string name)
    {
        _name = name;
    }
}

这是实现 DDD 模式的正确方法吗?
或者这是否违反了我不知道的 DDD 规则?

【问题讨论】:

  • 本身没有“DDD 模式”。 DDD 有一系列模式可供您选择使用。事实上,您的代码无法满足 DDD 的基本要求:丰富的域模型 - 您的实体没有行为或域逻辑,也没有强制执行不变量。

标签: c# .net .net-core domain-driven-design domain-model


【解决方案1】:

它本身并没有违反任何 DDD 规则 - 但由于以下几个原因,这种方法经常被劝阻:

  • DDD 鼓励您根据系统在管理状态的更改时需要支持的操作、流程和规则对域进行建模。
    • 您建模的关系可能存在于现实世界中 - 它们可能有助于数据可视化 - 但它们对于您的模型真的有必要吗?
  • DDD 中的良好做法是设计small 聚合。聚合确实是一个“一致性”边界——你的一致性边界越大,你就会产生一些后果:
    • 大多数操作并不涉及所有数据 - 但所有数据必须在每个操作期间以事务方式锁定
    • 在协作的多用户域中,这可能会导致并发问题,即任一用户由于他们想要操作的数据被不必要地锁定而被阻止
  • 为什么可能这样的关系对建模有用?
    • 如果您有一个规则(不变量)必须在所有子聚合中具有事务一致的数据,例如:
      • 每个供应商必须有最多 4 个目录 - 要执行此规则,您必须在供应商中拥有交易上一致的目录列表
      • 目录中目录商品的价格总和不得超过 $X - 同样,您需要以交易一致的方式处理所有商品

替代品

所以 - 如果您没有任何此类规则,并且您已被说服创建“小”聚合,您能做什么?

  • 每个实体都成为它自己的集合
  • 通过引用链接实体。在这种情况下:
    • 供应商将没有有目录列表
    • 目录将有一个“供应商 ID”以将目录链接到供应商,并有助于获取供应商的目录列表
    • 目录不会有 CatalogItem 列表
    • CatalogItem 将有一个“CatalogId”链接到目录 - 同样有助于按目录获取项目列表

这种方法的含义是您将在聚合之间具有事务一致性 - 但除非您的规则要求它,否则您不需要它,那么为什么要强制它呢?

您真的需要事务一致性吗?

DDD 鼓励的另一条建议是挑战对事务一致性的要求——这真的有必要吗?

使用上面的简单示例 - 如果供应商最终有 5 个目录会发生什么?世界会崩溃吗?即使您确实需要该规则,它是否需要在事务上保持一致?对于较小的聚合,您可以:

  • 如果供应商已经有 4 个目录,则包括客户端验证以防止操作
  • 在创建目录时发布事件,触发检查和补偿操作 - 如果处理程序确定供应商现在有 5 个目录,则发出警报或更新供应商状态直到用户删除目录,或自动使最旧的目录过期 - 在您的域中最有意义的目录

总结

建议是:

  • 设计小型聚合体
  • 拥抱最终的一致性

【讨论】:

    猜你喜欢
    • 2018-12-14
    • 2020-01-29
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    • 1970-01-01
    相关资源
    最近更新 更多