使用NHibernate的事件源

使用NHibernate的事件源,nhibernate,domain-driven-design,cqrs,event-sourcing,Nhibernate,Domain Driven Design,Cqrs,Event Sourcing,我正在从纯DDD范式转向CQRS。我目前关心的是活动采购,更具体地说,是组织活动商店。我已经读了很多博客文章,但仍然不能理解一些事情。如果我错了,请纠正我 每个活动基本上包括: -活动日期/时间 -事件类型(我们也可以从中找出AggregateRoot的类型) -聚合操作id(Guid) -AggregateRoot版本(用于维护更新顺序) -事件数据(某些序列化类,包含进行更新所需的数据) 现在,如果我的事件数据由简单的值类型(整数、字符串、枚举等)组成,那么就很容易了。但是如果我必须通过另一

我正在从纯DDD范式转向CQRS。我目前关心的是活动采购,更具体地说,是组织活动商店。我已经读了很多博客文章,但仍然不能理解一些事情。如果我错了,请纠正我

每个活动基本上包括: -活动日期/时间 -事件类型(我们也可以从中找出AggregateRoot的类型) -聚合操作id(Guid) -AggregateRoot版本(用于维护更新顺序) -事件数据(某些序列化类,包含进行更新所需的数据)

现在,如果我的事件数据由简单的值类型(整数、字符串、枚举等)组成,那么就很容易了。但是如果我必须通过另一个聚合操作怎么办?我不能将整个AR序列化为事件数据的一部分(考虑所有数据和延迟加载),基本上我只需要存储该AR的Id。但是,当我需要应用该事件时,我需要首先从数据库获取该AR。从我的域模型(调用存储库和使用AR ID)这样做是不对的

最好的方法是什么

p、 对于一个具体的例子,让我们假设有一个由任务和用户实体(都是AR)组成的模型。任务保留对负责用户的引用。但负责的用户是可以改变的


更新:我想我已经找到了困惑的根源。我认为事件源应该只用于构建阅读模型。在这种情况下,传递ID和原始数据是可以的。但在聚合本身上使用的事件相同。这一点我无法理解。

在DDD中,聚合是一致性/不变边界,因此一个人可能永远不会依赖另一个人来保持其不变。当我们开始使用此设计限制时,我们发现很少有情况需要存储对另一个的完整引用,通常我们存储其id和(如果需要)版本以及相关属性的副本


例如,使用常见的订单/行项目和产品问题,我们将在行项目中复制产品的id和价格,而不是完整的参考。这样可以防止产品价格的变化影响订单/行项目聚合的不变量。如果需要在产品价格更改后更新行项目价格,我们需要跟踪已用产品的价格更改事件,并向订单/行项目发送补偿命令。通常,这种协调/同步由一个传奇来处理。

在事件源中,聚合的状态由事件定义,仅此而已。所有域模型(ala DDD)都是用来决定应该引发哪些域事件的。事件应该对您的域一无所知,它应该是简单的DTO。事实上,在没有DDD的情况下使用事件源是完全可以的。

据我所知,事件源应该可以帮助人们摆脱关系数据模型和ORM(如NHibernate或实体框架),因为它们各自都是一门独立的科学。然后,程序员可以只关注业务逻辑。我在这里看到了一些用于事件存储的关系模式,它们只是ID、Version、Timestamp加上一个NClob或NVarchar(max)列来存储事件负载模式。

谢谢!我想我已经找到了困惑的根源。我认为事件源应该只用于构建阅读模型。在这种情况下,传递ID和原始数据是可以的。但我经常看到在聚合本身上使用相同的技术。这一点我无法理解。当然,但我需要DDD来处理实际应用程序的所有复杂业务逻辑。从DDD的角度来看,从一个AR到另一个AR是完全正常的。所以我必须以某种方式在我的事件中传递这些引用,并最终存储它们。是的,在域事件中有各种ID是可以的。我所说的事件引用了域类(这根本不起作用)。事件应该对域有很多了解。事件应封装已发生的与域相关的事实。你应该编辑一下。它应该是无逻辑的。我们都知道双向依赖是不好的。我很确定这里也不例外。我相信双向依赖并不完全是坏的,它们只是经常被误用(和滥用),而且更难实现。无论如何,在实际应用程序中,事件应该包含对域对象的引用。可能是Id(我个人不喜欢)。但不去存储库就不可能从我的域“应用”该事件,这很难看,特别是因为我很可能已经查询了它以检查一些业务规则。也许这只是一个良好基础设施的问题,或者我只是需要放弃一些DDD知识和自由来遵守CQR。看看这个博客: