在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
的东西吗?
答案 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
的关联(或链接)表来为其建模,并为与关联相关的任何数据添加列,例如数量和价格。但是,我们所使用的表格以某种方式称为OrderItem
或OrderLine
。我们这样做是因为让关联更接近订单是有意义的。
我有一篇关于此的博客文章仍然有些道理:http://www.ebenroux.co.za/design/2009/09/08/many-to-many-aggregate-roots/
在DDD世界中,我们不会让Order
保留对Product
个实例的对象引用列表。相反,我们会创建一个名为OrderItem
的VO,其中只包含ProductId
以及Quantity
,Price
和非规范化ProductDescription
,因为该描述可能会在之后发生变化订单已被放置,并且在历史上,这将改变订购的订单,这将是禁止的。
只是一些值得思考的事情:)