如何处理聚合根的并发约束

时间:2012-11-29 12:44:02

标签: domain-driven-design aggregateroot eventual-consistency

我担心我已经知道了答案,但我希望有人可以提供以前没有找到的替代解决方案。一如既往地根据Effective Aggregate Design做DDD比我想象的要困难,但这是我的情景。

  • 我们有两个AR,User和RoleGroup
  • 可以向用户授予特定的RoleGroup,从而获得该角色组中角色(集合值对象)提供的权限。角色组的身份在用户AR中保留为另一个VA。
  • 当从系统中删除RoleGroup时,我们引发一个域事件,处理程序使用该事件来查找引用该RoleGroup的所有用户并删除引用。相应的投影非规范化器将使用相同的事件来更新用户的有效角色。这是授予该用户的各个角色和所有已授予角色组的角色的组合。
  • 这不一定是交易性的(哇,它最终可以保持一致)。
  • 我们使用Jonathan Oliver的EventStore 3.0以及来自Lokad.CQRS和NCQRS的元素来使用事件采购。

因此,理论上,当一个请求(它是一个ASP.NET MVC应用程序)正在执行上述场景时,另一个请求可能会向用户授予相同的RoleGroup。如果在上述域事件处理程序扫描与该RoleGroup相关的用户之后发生这种情况,则该请求将完成。此时,您有一个已删除的RoleGroup(尽管不是物理上的)和仍然拥有该RoleGroup标识的User。

你怎么防止这种情况?我们目前正在考虑使用户的身份被授予该RoleGroup AR的特定RoleGroup部分,因此删除RoleGroup并将其授予用户将导致乐观的并发冲突。但不知何故,这不是正确的解决方案。

3 个答案:

答案 0 :(得分:1)

为什么要向User聚合添加RoleGroup引用?用户是否有使用此信息的不变量?

我认为通过RoleGroup聚合向用户授予RoleGroup可以更加简单地建模,从而发出类似RoleGroupGrantedToUser事件的内容。删除RoleGroup后,它会发出RoleGroupRemoved事件。在此事件之后,RoleGroup不再接受新用户。

答案 1 :(得分:1)

这类似于如何解决唯一性约束。

假设有一个角色组和用户都有SERIAL行为的投影。当角色组被归档时(即它们不能再被使用),位于投影顶部的被动位可以通知已被授予所述角色组的所有用户,他们不再是其中的一部分。同时将此归档角色组授予用户(或一组)时,可以利用投影的串行性质告诉该用户他们不再是该组的成员。

所有这一切,这只是家务。只有当角色组和用户使用时,正确的视图才是重要的。由于我假设角色组将携带一个IsArchived位,我可以安全地将它们过滤掉,而不必担心一些悬空边缘情况,我们仍需要证明它必须以自动方式解决。

另外,扫描事件日志也会显示这种情况,即是否有任何用户被授予在该时间点之前(或在该时间点之前)存档的角色组?管理员可以通过向用户聚合发出补偿命令来解决此问题。

“这取决于”TM

编辑:我已经为这个问题提供了技术解决方案。我鼓励其他读者探索不同的建模方法。解决这些问题。有时,甚至大多数时候,答案根本不是技术性的。 YMMV。

答案 2 :(得分:0)

为了防止这种情况,您可以使其成为事务性的,即无法通过某种锁定机制将删除的RoleGroup授予用户。但这只会使事情复杂化,正如您所指出的那样,并不是必需的。

当您将RoleGroup分配给用户时,我想您有一个类似的投影非规范化器来更新用户的有效角色。您可以检查当时是否仍存在已授予的RoleGroup,如果不存在,则从User中删除该引用。然后,用户的有效角色最终应该是一致的。