我的CQRS应用程序有一些复杂的域对象。创建它们时,实体的所有属性都由用户直接指定,因此
CreateFooCommand有大约15个属性。
FooCreatedEvent因此也有15个属性,因为我需要读取端的所有实体属性。
由于必须将命令参数分派给域对象,并且不应将FooCreatedCommand传递给域,
有一个从CreateFooCommand到域的手动映射。
由于域应该创建域事件,
这是从域Foo属性到FooCreatedEvent的另一个映射。
在读取方面,我使用DTO来表示Foo的结构,因为它存储在我的读模型中。
因此事件处理程序更新读取端会引入从事件参数到DTO的另一个映射。
为了实现一个简单的商业案例,我们有
我考虑过摆脱命令/事件参数并推送DTO对象,但这意味着域可以接收或创建DTO并将其分配给事件。
序列:
REST Controller --Command+DTO--> Command Handler --DTO--> Domain --(Event+DTO)--> Event Handler
关于使CQRS减少实施痛苦的任何想法?
答案 0 :(得分:4)
我看到以下选项:
创建一个由FooDetails
和CreateFooCommand
使用的不可变DTO类FooCreatedEvent
,方法是将其注入构造函数中; type提示针对FooDetails
的聚合方法;例如new CreateFooCommand(new FooDetails(prop1, prop2, ...))
创建由FooDetails
和CreateFooCommand
继承的不可变基类FooCreatedEvent
,并键入提示针对FooDetails
的聚合方法
完全更改样式并使用cqrs.nu提升的样式,其中命令直接发送到聚合;聚合具有FooAggregate::handle(CreateFooCommand command)
等命令方法;我个人经常使用这种风格。
答案 1 :(得分:1)
使用CQRS + ES,您选择了更复杂的方法,更多的移动部件,知道它可以让您实现更多。和它一起生活。这种方法的优势意味着分离问题。命令是命令,事件是事件等。虽然它们中的许多可能在链中看起来相似,但可能有例外。有些可能包含其他数据,或者相同数据的略有不同的方面。命令可以具有关于应用上下文(谁发起命令,何时,是重试等)的元信息,这些信息与域无关。阅读模型通常包括除了自己的信息之外还要显示的相关对象的信息(想想父子关系)。
在阻止自己对这些异常进行建模之前,只有那么多看似相似的代码可以切断。在这些数据结构之间引入继承或组合通常比必须编写样板映射代码的原始痛苦更复杂。