如何在CQRS + Event Sourcing架构中处理Add / Create *命令


11

我想使用CQRS模式和Event Sourcing来实现我的第一个应用程序。我想知道如何正确处理聚合根的创建。假设有人发送CreateItem命令。应该如何处理?事件ItemCreated应该存储在哪里?作为新项目的第一事件?还是我应该具有某种ItemList实体来聚合所有项目,并且其事件列表仅由ItemCreated事件组成?

乌迪·达汉 Udi Dahan)建议不要创建聚合根,而应始终使用某种获取方法。但是我如何获取新的东西,当然还没有分配任何ID。我理解背后的想法,并且认为一个新对象是其状态由零个事件组成的对象是很合理的。但是我应该如何使用呢?我的存储库中应该有一个与众不同的方法吗?getNewItem()还是让我的get(id)方法接受Optional<ItemId>

编辑:经过一段时间的挖掘,我发现使用actor对上述模式进行了非常有趣的实现。作者不是创建聚合,而是从某种具有新创建的UUID的存储库中检索聚合。这种方法的缺点是他允许出现临时的不一致状态。我也想知道如何delete使用这种方法来实现方法。只需将Deleted事件添加到聚合的事件列表中?


1
我怀疑Udi的职务有误导性。恕我直言,听起来他的真正目标是应该始终可以从其他地方访问新鲜制作的AR,其方式可以捕获有关为什么/如何/谁决定需要创建新AR的上下文。其他所有内容都与特定的实现(NHibernate?)如何使其更易于管理有关。
达里安(Darien)

2
请注意,您所引用的Udi Dahan文章明确指出,他的建议可能不适用于事件源:udidahan.com/2009/06/29/dont-create-aggregate-roots/…–
EZ Hart,

Answers:


13

据我所知,乌迪(Udi)的帖子中的想法是,没有任何物品可以凭空出现。(几乎)总是存在某些东西,或更具体地说,是某些域操作导致了项目的创建。就像Udi的例子一样,用户实际上是从注册该网站的访问者中诞生的。在这一点上和那个有界上下文中,Visitor是聚合根,它是通过其IP地址检索的。然后,此访问者此时通过称为Register的域操作创建一个新的“项目”,即用户。之前的步骤也是相同的,这是另一个有界上下文:引荐来源网址是AR,它是通过URL检索的,并且具有一个称为BroughtVisitorWithIp的域操作,该访问者是在此处出生的。

Udi在删除方面也写得很好:http : //www.udidahan.com/2009/09/01/dont-delete-just-dont/。主要思想是,您永远不会删除任何内容。后面总是有一个域操作,我们要捕获。就像订单被取消,而不是删除。阅读它,这是一个很好的帖子。

这两个帐户在执行DDD(尤其是事件源)时的要点是,永远不要执行直接的CRUD操作。如果您发现自己确实只需要插入,更新或删除一些数据,并且其后确实没有域操作,那么DDD和Event Sourcing可能不适合该有限上下文。只要一个有限的上下文遵循一个原则,您就可以随意组合这两个对象。这样,CRUD样式的有界上下文可以在数据库中创建某些行,该行成为另一个有界上下文中的一个实体和一个聚合根,您现在可以在其中检索AR而不必创建它。


2
“也许DDD和Event Sourcing不太适合那种有限的上下文。” 您正确理解了DDD。不应仅出于撒但的荣耀而在每种情况下都应实施此方法,而应仅在需要处理充满不确定性规则的复杂领域时实施。我个人是为法律软件设计的,它的需求不是逻辑驱动的。
Yegor Chumakov

2
仅针对此句子“针对该有限上下文” +1 :)
Songo

2
+1使用动词“添加”和“创建”强烈暗示您仍在考虑与良好的旧表格数据库进行交互方面的域。在不了解您的域/边界上下文的情况下,我不能说这是否合适。忽略持久性,首先专注于您的域特有的命令和事件(又名意图和结果),然后担心如何保持状态,这是数十万次以前解决过的问题。
马特

“使用动词“添加”和“创建”强烈暗示您仍在考虑与良好的旧表格数据库进行交互方面的域”。当您的UI设计中有一个很大的“添加内容”按钮时,可悲的是,这就是意图。从字面上添加新的东西。我通常同意您的意见,但是我们在这里不是在谈论数据库级别,有时“添加”或“创建”实际上是正确的用法。
designermonkey

1
@designermonkey当您在UI中有这些按钮时,它们后面是否真的有域操作?也许,但是十分之九的情况下,实际上确实不需要在该受限上下文中进行复杂的域操作。纯CRUD操作就是纯CRUD操作,应该这样处理。仅当需要领域模型的复杂性时,才应使用它。因此,不同的边界上下文具有不同的设计原理。
Tuukka Haapaniemi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.