2011-12-06 46 views
10

我有一个简单的两个聚合根和一个正则实体的检查域。 TenantUserGroupUser这种特定样品中TenantUser弥补两个AggregateRoots域事件处理程序什么时候开始使用?

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

可以说,User不应该是一个AggregateRoot可言,但因为它会被别人引用,它不可能是一个普通的实体。 (是的?)

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

它生成一个带有Date,AggregateVersion和AggregateId(用户)的DomainEvent。现在我们到了模糊的部分。

打开提交此事件到商店,此事件广播到公共汽车(内存,无论)。这就是域的事件处理程序(类似于命令处理程序)捕获创建的用户并通知/操纵TenantUserGroup以添加UserId

我的想法是解决这个问题的方向是完全错误的吗?

+1

您可以通过重新考虑您的模型来简化您的问题。当您需要跨界有限的上下文通信时,或者您希望支持业务逻辑(例如电子邮件通信)来响应域事件时,域事件会很有帮助。你的模型是否需要多个有界的上下文?您是否可以在服务层中包含所有必需的操作,例如UserService? – eulerfx

+0

你应该经常检查你是否不能模拟这个问题。然而,在这种情况下,它是一个人为的例子,旨在获得关于不同有界AR之间的通信应如何发生的答案。 – Jaapjan

+0

“UserGroup中的未来行为需要UserId?”是一个非常重要的问题(否则你为什么要在聚合之间进行交流)。如果您的域名不是多租户(不要与多租户混淆为非功能性需求),让租户成为您域名的一部分似乎很奇怪。如果他们在同一个BC中,请使用您的域对象与一些TDA进行协作。 –

回答

6

A 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); 
    } 
} 

了解更多关于this article传奇由里纳特阿卜杜林或乌迪大汉看"CQRS, race conditions, and sagas - oh my!"

更新:

我们扩展后在评论中的讨论我将尝试展示这可以从另一个角度如何工作(前面的伪代码)。希望这可以解决一些可能的解决方案:

// 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 
+0

如果可能的话,如果我有正确的顺序,你可以点亮吗?改变AR,承诺ES,广播事件,Saga选择并更改其他AR等等?这需要一些机制来唤醒,instanciate并定期致电佐贺的,是的? – Jaapjan

+0

这正是我想到的顺序。像任何其他事件处理程序一样,基本的无状态saga实现可以简单地在启动时注册。更复杂的实现可能包括持久性。对于初学者来说,简单的无状态实现应该足以适应这个概念。对于更复杂的变体,请查看NServiceBus和Jonathan Oliver在GitHub上的Common Domain/Event Store的传奇故事。 –

+0

在这种特殊情况下,由于用户创建的事件可能不会立即被传奇人士拿走,我们正在处理域中的最终裁决,是的?由于用户可能已被“添加”到租户的组,但租户AR尚未更新? – Jaapjan

相关问题