在域驱动设计中获取聚合的正确方法

时间:2016-03-09 19:39:10

标签: c# domain-driven-design

DDD架构中,我有一个Order聚合根和一个Product聚合。当我想将Product添加到特定Order时,我会这样做:

class Order
{
  void AddProduct(Product p)
  {
    this.Products = p;
  }
}

然后,OrderRepository将内存中Order.Products收藏品持久存储到数据库中。

我的问题是:如何针对特定Product获取具体的Order?鉴于我们不应该将存储库注入实体,我不确定如何补充内存中的Order.Products集合:

class Order
{
  Product GetProduct(int productID)
  {
    return this.Products.Where(x => x.ProductID == productID);
  }
}

或者这是属于OrderRepository的东西吗?

2 个答案:

答案 0 :(得分:3)

class Order
{
    void AddProduct(Product p)
    {
        this.Products = p;
    }
}

这个模型可能不对。

(1)如果Product的状态需要满足Order中的业务不变量,那么Product应该是订单聚合中的实体,但也不是它的单独聚合自己的。

另一方面,如果Order不需要了解Product的状态来满足自己的不变量,那么Products集合不应该包含产品,而是其他东西(可能是Id<Product>

提示:通过更改Product来修改Order是否有意义?

(2)对Order聚合的大多数讨论得出的结论是,订单包含OrderItems的集合(注意:不是聚合),其中每个OrderItem包含引用到产品聚合。

购物车是DDD讨论中相当常见的示例案例

答案 1 :(得分:3)

我知道这个问题有一个公认的答案,但无论如何我都会发表意见:)

聚合根(AR)永远不应该引用另一个AR。它只使用相关AR的Id或包含相关AR的Id的值对象(VO)以及一些可选的额外数据。

关于Order - &gt;的有趣之处Product关系是它在数据库术语中是典型的多对多关系。在数据库世界中,人们通常会通过创建名为OrderProduct的关联(或链接)表来为其建模,并为与关联相关的任何数据添加列,例如数量和价格。但是,我们所使用的表格以某种方式称为OrderItemOrderLine。我们这样做是因为让关联更接近订单是有意义的。

我有一篇关于此的博客文章仍然有些道理:http://www.ebenroux.co.za/design/2009/09/08/many-to-many-aggregate-roots/

在DDD世界中,我们不会让Order保留对Product个实例的对象引用列表。相反,我们会创建一个名为OrderItem的VO,其中只包含ProductId以及QuantityPrice和非规范化ProductDescription,因为该描述可能会在之后发生变化订单已被放置,并且在历史上,这将改变订购的订单,这将是禁止的。

只是一些值得思考的事情:)