域事件处理程序什么时候开始发挥作用?

Jaa*_*jan 10 c# events domain-driven-design cqrs domain-events

我有一个简单的两个聚合根和一个常规实体的检查域. Tenant,UserGroup以及User在这个特定样本中的位置TenantUser弥补两个AggregateRoots.

当从UI /服务层接收到命令时,它到达操作只写域的命令处理程序.

您可以说User根本不应该是AggregateRoot,但由于它将被其他人引用,因此它不能是常规实体.(是?)

这两个AggregateRoot需要进行通信.A User不能在不属于a的情况下创建,a UserGroup是有界上下文中的实体Tenant.据推测,我们可以通过构造函数创建一个用户,因为它是一个简单的约束.User.Create(TenantId, UserGroupId)

它生成一个DomainEventwith Date,AggregateVersion和AggregateId(用户).现在我们来到模糊的部分.

打开将此事件提交到商店,此事件将被广播到总线(内存,无论如何).这一点,该点域的事件处理程序,类似命令处理,抓创建的用户,并通知/操纵TenantUserGroup添加UserId

我对解决这个问题的想法是否会走向完全错误的方向?

Den*_*aub 7

一个Saga可能是你在找什么.

简单地说:一个saga可以实现为一个事件处理程序,它监听特定事件并向不同的聚合根或甚至跨上下文边界发出命令.

在您的情况下,它可能看起来像这样:

public class RegisterUserSaga : Handles<UserCreated>
{
    public void Handle<UserCreated>(UserCreated evnt) {
        var tenantId = // you probably know how to find this
        var groupId =  // same here
        var command = new RegisterUserForTenant(evnt.UserId, tenantId, groupId);
        Bus.Send(command);
    }
}
Run Code Online (Sandbox Code Playgroud)

在Rinat Abdullin的这篇文章中阅读更多关于传奇的内容,或者观看"CQRS,竞争条件和传奇 - 哦,我的!" 作者:Udi Dahan

更新:

在我们在评论中进行了扩展讨论之后,我将尝试从不同的角度展示这是如何工作的(伪代码).这有望为可能的解决方案提供更多信息:

// Aggregates:

Tenant
    Guid TenantId
    List<Guid> UserGroups

UserGroup
    Guid UserGroupId
    List<Guid> Users

User
    Guid UserId
    Some more details

// Commands:

RequestRegistration(userId, userGroupId, user details)
CreateUser(userId, user details)
AddUserToGroup(userId, userGroupId)

// The initial command would be:

RequestRegistration (leading to a RegistrationRequested event)

// The Saga handles the RegistrationRequested and all subsequent events

UserRegistrationSaga 
    Handle(RegistrationRequested)
    -> send CreateUser command (which eventually leads to a UserCreated event)
    Handle(UserCreated)
    -> send AddUserToGroup command (-> UserAddedToGroup event)
    Handle(UserAddedToGroup)
    -> Done
Run Code Online (Sandbox Code Playgroud)