【问题标题】:DDD considering Repositories & Services for entitiesDDD 考虑实体的存储库和服务
【发布时间】:2020-03-29 17:54:54
【问题描述】:

我已经熟悉DDD 并试图了解EntitiesAggregate Roots 的交互方式。

以下是情况示例:

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


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

我遇到的 DDD 规则:

  • 规则:只有aggregate root 可以访问存储库。

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

  • 规则:aggregate外的Entities只能通过aggregate root访问aggregate内的其他entities

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

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

【问题讨论】:

    标签: domain-driven-design ddd-repositories ddd-service


    【解决方案1】:

    只有聚合根才能访问存储库

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

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

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

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

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

    当然可以;为此,您首先加载 User 聚合的根实体,然后调用该实体上的方法来获取您需要的信息。

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

    四五年后出现,进一步完善了这个想法——事实证明,在只读用例中,领域模型不一定有很大贡献;如果它们已经被满足并且你没有改变任何东西,你就不需要担心不变量。

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

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

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

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

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

    【讨论】:

    • 感谢您的洞察力,所以谈到第 2 点,您提到 “您将通过首先加载用户聚合的根实体来做到这一点” 这是否意味着我需要先去 UserRepo 并拉出用户然后拉出电子邮件,我不能让 EmailService 直接与 Email Repo 交谈(query like Select * from emails where user = some@email.com)。从您回答的后半部分来看,我想我可以做到,但我只是在确认。也请您详细说明最后几句话“展示原始护理”
    • 查看答案的修改
    • 我们可以把它移到一个快速聊天窗口吗?因为由于某种原因,我无法将其包裹在我的头上,因为电子邮件实体虽然只是用户聚合下的任意实体,但它确实有自己的 ID 和生命周期以及与其他实体交互的方式。这是否意味着电子邮件本身很可能是一个聚合?也许吧,但我将它们放在同一个集合中的原因是因为没有用户的电子邮件是没有意义的。
    猜你喜欢
    • 2013-12-05
    • 1970-01-01
    • 2010-11-24
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 2013-02-19
    • 2012-03-10
    相关资源
    最近更新 更多