我正在努力思考如何正确地使用存储库模式。聚合根的核心概念不断出现。当我在web和Stack Overflow上搜索什么是聚合根时,我一直在寻找关于聚合根的讨论,以及指向应该包含基本定义的页面的死链接。

在存储库模式的上下文中,什么是聚合根?


当前回答

聚合是通过限制聚合根的访问来保护不变量和强制一致性的地方。不要忘记,聚合应该根据您的项目业务规则和不变量进行设计,而不是数据库关系。不应该注入任何存储库,也不允许进行任何查询。

其他回答

假设你有一个计算机实体,这个实体也不能没有它的软件实体和硬件实体。这些组成了计算机集合,即域的计算机部分的微型生态系统。

聚合根是聚合(在我们的例子中是Computer)中的母实体,通常的做法是让存储库只与聚合根的实体一起工作,并且这个实体负责初始化其他实体。

将聚合根视为聚合的入口点。

在c#代码中:

public class Computer : IEntity, IAggregateRoot
{
    public Hardware Hardware { get; set; }
    public Software Software { get; set; }
}

public class Hardware : IEntity { }
public class Software : IValueObject { }

public class Repository<T> : IRepository<T> where T : IAggregateRoot {}

请记住,硬件也可能是一个ValueObject(本身没有标识),仅将其视为一个示例。

来自DDD Step By Step(离线):

在一个聚合中有一个聚合根。聚合根为 属性中的所有其他实体和值对象的父实体 聚合。 存储库对聚合根进行操作。

更多信息也可以在这里找到。

聚合是通过限制聚合根的访问来保护不变量和强制一致性的地方。不要忘记,聚合应该根据您的项目业务规则和不变量进行设计,而不是数据库关系。不应该注入任何存储库,也不允许进行任何查询。

在另一个世界中,在事件源中,聚合(根)是一个不同的概念。 事件源可能与CQRS、DDD等一起遇到。

在事件源中,聚合是一个对象,其状态(字段)没有映射到数据库中的记录,因为我们习惯于在SQL/JPA世界中思考。

不是一组相关的实体。

它是一组相关的记录,类似于历史表。

GiftCard。amount是GiftCard Aggregate中的一个字段,但是这个字段被映射到所有创建的事件,比如卡兑换(从卡中取钱)。

因此,聚合的数据源不是数据库中的记录,而是为特定聚合创建的事件的完整列表。我们说我们的事件源聚合。

现在我们可以问问自己,这是怎么做到的?谁在聚合这些事件,我们仍然使用一个字段,例如giftcard。amount?我们可能期望这个数量是一个集合,而不是一个大十进制类型。

是事件来源引擎,负责工作,它可能只是按创建顺序重播所有事件。但这超出了本线程的范围。

聚合根是一个简单概念的复杂名称。


一般的想法

设计良好的类图封装了它的内部结构。访问该结构的点称为聚合根。

解决方案的内部结构可能非常复杂,但是这个层次结构的用户将只使用root. dosomethingwherehasbusinessmeaning()。


例子

检查这个简单的类层次结构

你想怎样驾驶你的车?选择更好的API

选项A(它只是以某种方式工作):

car.ride();

选项B(用户可以访问类内部内容):

if(car.getTires().getUsageLevel()< Car.ACCEPTABLE_TIRE_USAGE)
    for (Wheel w: car:getWheels()){
        w.spin();
    }
}

如果你认为选择A更好,那么恭喜你。你得到了根集合背后的主要原因。


聚合根封装多个类。您只能通过主对象操作整个层次结构。