2

我只是想摆脱存储库/服务/演示的典型 N 层架构的舒适区,并开始使用聚合查看 DDD,我不得不承认我有点困惑,希望有人能澄清以下内容例子:

如果我有一个名为 News、NewsImage 和 Customer 的实体,它们都是 EF 可持久对象,如下所示:

public class Customer
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class NewsImage
{
    public virtual int Id { get; set; }
    public virtual byte[] Data { get; set; }
    public virtual News News { get; set; }
}

public class News
{ 
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<NewsImage> NewsImages { get; set; }
    public virtual Customer Customer { get; set; }
}

据我了解,这些可能是我们用来将域对象持久保存到数据库的对象,但如果我们使用来自域模型的聚合,我们可能会有这样的东西:

public class NewsAggregate
{
    public int Id { get; set; }
    public string Name { get; set }

    public void AddImageToNews(byte[] imageData)
    {
         // Hide NewsImage or that object and add the byte[] data here?
    }
}

我的问题如下,我很感激任何澄清,因为我确定我误解了这里的基本原则:

  1. 只有聚合对象应该暴露给表示层(或任何消费层)。
  2. 如何处理将聚合对象转换/持久化到数据库,我可以使用映射,这很好,但是我怎么知道我是在创建对象还是在更新(如果设置了 Id,它是否是瞬态的?) . 我如何知道是否已添加新图像以及更新或删除哪些图像?我认为我遇到的问题是我调用 create 将新闻聚合传递给存储库并创建它,然后我可以从通过 EF 实体填充的域中获取聚合,然后添加图像,当我传递新闻聚合时返回 我如何知道为了创建/更新数据而发生了什么变化?
    1. 客户应该去哪里,是否应该作为 AddCustomer 方法在新闻聚合对象上,是否应该有一个具有 AddNews 方法的 CustomerAggregate 以及这两个选项如何持续存在?

非常感谢您的任何见解,我一直在阅读并查看示例项目,这些项目展示了这个概念,但似乎并没有完全解释实现这一目标的最佳方法。

4

2 回答 2

5

首先:DDD 不建议您使用任何特定的架构。我在 DDD 中使用了许多不同的架构,您应该使用对任务有益的架构。显然,如果以数据驱动的方式思考,DDD 会遇到很多问题。

DDD 是一种旨在应对复杂业务规则的方法。如果您的应用程序价值在于技术资产(如在云中、公开 Web 服务或一些漂亮的 html5/移动 UI),则不应使用它,而是在于它处理的业务的复杂性。
您不应该将 DDD 用于简单的业务规则。经验法则是:如果您不需要领域专家来了解业务,那么您根本不需要 DDD。

然后,要正确理解聚合,您应该阅读 Vernon关于该主题的文章。那篇文章解释说,存在聚合是为了确保业务不变量。你不应该仅仅为了优化数据库访问而使用聚合。

于 2013-03-31T15:45:11.803 回答
2

1)这取决于容量。有一条规则规定聚合只能直接引用其他聚合 - 而不是其他聚合中包含的实体或值对象。这是为了强制聚合作为一致性边界——它们完全封装了它们“聚合”的内容。每个聚合应该有一个存储库。表示层和任何外层都可能需要以两种通用能力引用聚合 - 用于显示目的或行为目的。聚合不应该过多关注它的显示方式,因为可以使用更适合该任务的不同模型来实现查询 -读取模型. 相反,聚合应该关注行为。是的,在表示层希望在聚合上执行行为的情况下,它应该通过其身份引用聚合。更好的是,创建一个应用程序服务来封装领域层并将行为公开为一个简单的外观。

此外,聚合不是单个类,而是通常围绕作为实体的聚合根聚集的一组类。您不一定需要一个单独的类来表示聚合,它可能只是根实体。

2) 对于持久性,您似乎正在使用 EF,它应该为您处理所有更改跟踪。它应该跟踪哪些对象是持久的或哪些是瞬态的。诸如 NHibernate 之类的 ORM 也可以做到这一点。

2.1) 这取决于Customer它本身是否是一个聚合体。如果是这样,News则应Customer仅通过 ID 引用。此外,新闻实体可能需要客户,在这种情况下,应将客户 ID 传递给新闻实体的构造函数。如果不需要,则存在将客户与新闻实体相关联的行为。从领域的角度考虑这一点 - 将客户与新闻实体相关联的含义是什么?尝试摆脱以技术、CRUD 方式AddCustomer思考,更多地考虑周围的业务意图。

正如Giacomo Tesio所指出的,DDD 在业务逻辑有些复杂的领域中显示出它的价值。如果您的所有行为都可以映射到 CRUD,则将其保留为 CRUD。否则,请在您的领域中寻找行为,而不是专注于数据。您的实体和值对象应尽可能地公开行为并隐藏状态。请阅读并重新阅读参考文章:Vaughn Vernon 的有效聚合设计

于 2013-03-31T16:59:46.497 回答