关于如何使用CQRS EventSourcing实现DDDD有很多话题,并且有一些示例实现……总而言之,这可能会令人困惑……
在Gregs视图中,聚合没有getter或setter – 只是发出相应事件的状态更改方法.
基本上,事件描述了过去发生的状态转换.它的数据描述了改变了什么.
有人说,这些数据可以通过其他数据“丰富”.
这些额外数据可以从哪里来?
即我有用户和用户组 – 两个聚合根(可以独立存在,具有身份).用户有一个名为AddToUsergroup的方法.
public class User : AggregateRoot { // ... public void AddToUsergroup(Usergroup usergroup) { // validate state RaiseEvent(new UserJoinedUsergroup(this.Id,usergroup.Id)); } // ... } public class Usergroup : AggregateRoot { private string _displayName; // ... public void ChangeDisplayName(string displayName) { // validate state RaiseEvent(new DisplayNameChanged(this.Id,displayName)); } public void Apply(DisplayNameChanged e) { this._displayName = e.DisplayName; } // ... }
如果我想用Usergroup的名称“丰富”事件(出于调试原因或类似的原因),我该怎么做?
>吸气剂不存在
>用户组的内部状态不可访问
>读取端存储库
>事件存储库
底线问题:
>可以将像存储库这样的东西注入聚合根吗?
>事件是否仅使用通过参数和聚合的内部状态提供的数据?
>事件是否只包含描述状态变化的最小数据?
而且(很少偏离主题,但样本在这里)
> AddToUsergroup应该使用Guid而不是完整的聚合根吗?
期待您的回答!
LG
warappa
解决方法
Should something like repositories be injected to aggregate roots?
不,在这种情况下没有必要.将域服务传递给聚合上的行为方法可能是合适的,但在这种情况下不再需要.
Should a event only use data available through parameters and internal
state of the aggregate?
是的,原始域事件应该是这样的,它可以很容易地由聚合构建,并且可以以确定的方式重放.
Should events only contain the minimum data describing the
state-change?
是.但是,为了满足外部用户的需求,这就是content enricher发挥作用的地方.要在外部调度域事件,首先将其提交到事件存储,然后您可以在相同的tx中调度,或者具有在外部发布事件的进程外机制.在外部发布时,您通常会使用不同的邮件合同,因为订阅者可能需要的内容比域事件本身更多.在这种情况下,您需要用户组名称.然后,发布者可以提取用户组名称并将该数据放入丰富的事件中.此发布者可以访问用户组的读取模型存储库,以便检索该名称.
Should AddToUsergroup take an Guid instead of an full aggregate root?
是.传递整个聚合可能是不可能的,并且还会产生一种错觉,即可能会使用除ID以外的其他内容,但情况并非如此.