我正在努力研究聚合和聚合根。我有一个自然聚合根,适用于大约60%的用户请求。即这些请求自然适用于聚合根。
在我的聚合中,我有另一个实体,它只能作为聚合根的成员存在。但是,用户将被告知这个其他实体对象。从概念上讲,用户有时可以直接对这个非聚合根对象进行操作。
所以,我认为我有几个选择:
请注意,顶级聚合根将包含此其他实体的集合。
示例:
主要聚合根:汽车
第二个实体:座位(根据类型,汽车有2个或4个座位)。在我的域名中,座位只能作为汽车的一部分存在。
域中的大多数操作都在Car级别。所以这将是聚合根的一个很好的候选者。然而,(我在这里努力争取示例),一些操作将在座位级别,例如, SpillCoffee,ChangeFabric,Clean ....
座椅和汽车都可以是聚合根吗?或者我应该始终从汽车开始?
由于
答案 0 :(得分:13)
聚合的想法是保证一致性,成为负责数据完整性和强制不变量的根。
假设有一条规则,例如“所有座位的布料必须相同”,或者“如果车内有人,你只能将咖啡洒在座位上”。一旦执行这些规则,将会更加难以执行。客户将能够单独更改结构,或者需要将这些不变量强制到外面(危险区域)。
恕我直言,如果完整性或强制不变量不是问题,那么实际上并不需要聚合。但是,如果有必要,我的建议是用汽车开始一切。但总是想到这个模型。如果有这样的不变量,那么谁强制执行这些不变量?然后尝试将这个想法传递给代码,一切都应该没问题。
答案 1 :(得分:2)
可能您需要对域模型的某些方面有更深入的了解。这个问题表明,您将要创建一种组织实体来提供系统的方法,理想情况下,在实施之前已经回答了这类问题。
当仅在系统实施中弹出时,您是回去查看域还是发现了一些脆弱性,其反馈可以 - 而且应该 - 聚合对业务相关细节的更改,以使域更丰富,更好地建模。
在汽车示例中,我使用了两个聚合的方法来关联不同的上下文。第一种方法是“汽车有座位”的方法,在这种情况下,“座位”的可能行动将只是“座位作为汽车的一部分”的意义。示例:清洁。
第二个聚合将在“座位”的背景下,并且座位可能作为独立的可能行动和配置。示例:ChangeFabric,ColorList。通过这种方式,聚合“汽车”具有“座位”,但客户可以知道有意义的上下文。哪个是危险的,就像samuelcarrijo在上一篇文章中所说的那样。如果上下文之间的修改影响域完整性,则会丢失所有聚合概念。
答案 2 :(得分:1)
对于带有购物车和订单项的购物车,我将这两个作为聚合根,因为我经常单独修改它们。
public class Cart : IAggregateRoot
{
public List<LineItem> LineItems {get;}
}
public class LineItems : IAggregateRoot
{
public List<LineItem> LineItems {get;}
}
但是,我对订单有一个单独的有界上下文,在这种情况下,我只需要有一个聚合根,因为我不再需要独立修改订单项。
public class Order : IAggregateRoot
{
public List<LineItem> LineItems {get;}
}
另一种选择是有一种从子ID中查找聚合根的方法。
Car GetCarFromSeatID(guid seatID)