【发布时间】:2017-11-01 04:45:33
【问题描述】:
为了说明问题,我们使用一个简单的案例:有两个聚合 - Lamp 和 Socket。必须始终执行以下业务规则:Lamp 和 Socket 都不能同时连接多次。为了提供适当的命令,我们设想了一个 Connector-service 和 Connect(Lamp, Socket)- 方法来插入它们。
因为我们要遵守一个事务应该只涉及一个聚合的规则,所以不建议在Connect-transaction 中为两个聚合设置关联。所以我们需要一个代表Connection 本身的中间聚合。所以Connect-transaction 只会用给定的组件创建一个新的Connection。不幸的是,此时麻烦开始了。我们如何保证连接状态的一致性?可能会发生许多同时用户想要在完全相同的时间插入相同的组件,因此我们的“一致性检查”不会拒绝该请求。新的Connection-aggregates 将被存储,因为我们只锁定在聚合级别。系统会在不知情的情况下不一致。
但是我们应该如何设置聚合的边界以确保我们的业务规则?我们可以设想一个Connections-aggregate,它收集所有活动连接(如Connection-entity),从而启用我们的锁定算法,该算法将正确拒绝重复的Connect-requests。另一方面,这种方法效率低下且无法扩展,而且在领域语言方面也违反直觉。
你知道我错过了什么吗?
编辑:总结问题,想象一个聚合User。由于聚合的定义是基于事务的单元,我们可以通过锁定每个事务的单元来强制执行不变量。一切都很好。但是现在出现了一个业务规则:用户名必须是唯一的。因此,我们必须以某种方式使我们的总边界与这一新要求相协调。假设有数百万用户同时注册,这将成为一个问题。我们试图在非锁定状态下确保此不变量,因为多个用户意味着多个聚合。
根据 Eric Evans 的“领域驱动设计”一书,只要单个事务中涉及多个聚合,就应该应用最终一致性。但这里真的是这样吗?这样做有意义吗?
在这里应用最终一致性需要注册User,然后使用用户名检查不变量。如果两个Users 实际设置了相同的用户名,系统将撤消第二次注册并通知User。想到这种情况让我感到不安,因为它扰乱了整个注册过程。例如,发送确认电子邮件必须延迟等等。
我想我只是忘记了一般情况,但我不知道是什么。在我看来,我需要Repository-level 上的不变量之类的东西。
【问题讨论】:
-
你有没有试过看看现实生活中的事情是如何发生的? DDD 是关于域的,在这个问题中,域是我们生活的现实。
-
我认为你应该重命名这个问题,因为“双向关联”在 DDD 中指的是不同的东西——即相互引用的实体。在这里,我们讨论的是跨越多个聚合(可能不仅仅是两个)的事务和不变量,无论对象是否具有双向引用。
标签: domain-driven-design aggregate bidirectional boundary