0

我一直在熟悉DDD并试图了解这种方式EntitiesAggregate Roots互动方式。

以下是该情况的示例:

假设有一个用户,他/她有多个电子邮件地址(例如,最多可以有 200 个)。每个电子邮件地址都有自己的身份,用户也是如此。用户和他们的电子邮件之间存在one to many关系。


从上面的例子中,我认为UsersEmails作为两个实体,Usersaggregate root

我遇到的 DDD 规则:

  • 规则:只能aggregate root访问存储库。

问题 1:这是否意味着我不能有一个单独的数据库表/集合来单独存储电子邮件?这意味着电子邮件必须嵌入到用户文档中。

  • 规则: Entities外部aggregate只能通过 via访问其他entitiesaggregateaggregate root

问题 2:现在考虑我确实将它们分成两个不同的表/集合,并通过在电子邮件中有一个名为的字段来链接电子邮件,该字段associatedUserId包含对电子邮件所属用户的引用。我不能直接拥有类似的 API 端点/users/{userId}/emails并直接在EmailService.getEmailsByUserId(String userId)? 如果不是,我该如何建模?

如果这个问题看起来有点太天真,我很抱歉,但我似乎无法弄清楚。

4

1 回答 1

1

只有聚合根有权访问存储库

这是否意味着我不能有一个单独的数据库表/集合来单独存储电子邮件?这意味着电子邮件必须嵌入到用户文档中。

这意味着如果您要对聚合的任何成员实体进行任何更改,则应该获取一个锁。这当然意味着聚合的数据表示存储在单个数据库中;但是您当然可以将信息分布在该数据库中的多个表中。

早在 2003 年,使用关系数据库作为记录簿很常见;一对多关系通常会涉及同一个数据库中的多个表。

聚合之外的实体只能通过聚合根访问聚合中的其他实体。

我不能直接拥有像 /users/{userId}/emails 这样的 API 端点并直接在 EmailService.getEmailsByUserId(String userId) 中处理它吗?

当然可以; 您将通过首先加载用户聚合的根实体,然后调用该实体上的方法来获取您需要的信息来做到这一点。

一个观点:Evans 反对应用程序应该能够直接操作域模型中的任意实体的想法。相反,应该只允许应用程序访问域模型中的“根”实体。实际上,该限制意味着应用程序并不真正需要了解由多个实体共享的约束。

四五年后出现,进一步完善了这个想法——事实证明,在只读用例中,领域模型的贡献并不大;如果它们已经满足并且您没有更改任何内容,则您无需担心不变量。

实际上,这表明GET /users/{userId}/emails可以将数据从只读视图中提取出来,而根本不需要涉及域模型。但POST /users/{userId}/emails需要证明原来的关心(意思是,我们需要通过领域模型修改数据)

这是否意味着我需要先去 UserRepo 并拉出用户然后拉出电子邮件,我不能让 EmailService 直接与电子邮件回购对话吗

在 Evans 的原文中,存储库提供对根实体的访问权限,而不是任意实体。因此,如果“电子邮件”是“用户聚合”中的一个实体,那么它通常不会有自己的存储库。

此外,如果您发现自己与该想法作斗争,则可能是一种“代码味道”试图让您认识到您的聚合边界在错误的位置。如果电子邮件和用户处于不同的聚合中,那么您当然会使用不同的存储库来获取它们。

诀窍是要认识到聚合设计反映了我们如何锁定数据以进行修改,而不是我们如何链接数据以进行报告。

于 2020-03-30T02:02:04.517 回答