我正在从纯粹的 DDD 范式转向 CQRS。我目前关注的是事件溯源,更具体地说,是组织事件存储。我读过很多博客文章,但仍然无法理解一些东西。所以如果我错了请纠正我。
每个事件基本上包括: - 事件日期/时间 - Event 的类型(我们也可以从中找出 AggregateRoot 的类型) - 聚合根 ID(Guid) - AggregateRoot版本(维护更新顺序) - 事件数据(一些序列化类,其中包含更新所需的数据)
现在,如果我的事件数据由简单的值类型(整数、字符串、枚举等)组成,那么这很容易。但是如果我必须传递另一个 AggregateRoot 怎么办?我无法将整个 AR 序列化为事件数据的一部分(考虑所有数据和延迟加载),基本上我只需要存储该 AR 的 Id 。但是,当我需要应用该事件时,我需要首先从数据库获取该 AR。从我的域模型(调用存储库并使用 AR Id)中这样做感觉不对。
最好的方法是什么?
附:举一个具体的例子,我们假设有一个由任务和用户实体(均为 AR)组成的模型。任务保留对负责的用户的引用。但负责的用户可以更改。
更新:我想我已经找到了困惑的根源。我认为事件溯源应该仅用于构建读取模型。在这种情况下,传递 ID 和原始数据就可以了。但同样的事件也用在聚合本身上。这是我无法理解的。
最佳答案
在 DDD 中,聚合是一致性/不变性边界,因此一个人可能永远不会依赖另一个人来维持其不变性。当我们开始使用这个设计限制时,我们发现很少有需要存储对另一个的完整引用的情况,通常我们存储它的 id 和(如果需要)版本以及相关属性的副本。
例如,使用通常的订单/订单项和产品问题,我们将在订单项中复制产品的 ID 和价格,而不是完整的引用。这种方式可以防止产品价格的变化影响订单/订单项聚合的不变量。如果在产品价格更改后有必要更新 LineItem 价格,我们需要跟踪已使用产品的 PriceChanged 事件并向订单/LineItem 发送补偿命令。通常这种协调/同步是由传奇来处理的。
关于nhibernate - 使用 NHibernate 进行事件溯源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6621803/