【问题标题】:Repository and Aggregate Roots in Domain Driven Design领域驱动设计中的存储库和聚合根
【发布时间】:2017-09-07 18:58:30
【问题描述】:

我正在构建一个通知系统,其中我的用户可以创建订阅,这些订阅定义何时将通知发送给他们以及通过哪个端点发送。我已经确定一个用户是一个聚合根,并且将为他们提供一个存储库。不过,我在理解这个概念时遇到了一些麻烦。据我了解,只能从存储库中提取聚合根。

假设我有一个用户

public class User
{
    public ICollection<Subscription> Subscriptions {get; set;}
    public ICollection<Endpoint> Endpoints {get; set;}
}

此用户拥有订阅和端点的集合。这两者都是实体本身,因为它们的内容可以改变而不是不同的对象。例如,这两个实体都可以启用/禁用。它们不能存在于用户上下文之外,因为只有用户才能创建订阅或端点。

我的订阅还包含对端点的引用,因为此订阅需要知道在哪里交付。

public class Subscription
{
    public ICollection<Endpoint> Endpoints {get; set;}
}

所以,由于我已将用户定义为聚合根,我现在有一个 UserRepository 用于持久化我的用户。对端点或订阅的任何修改都将在用户作为聚合根的上下文中完成。这对我来说很有意义。但是,如果我想检索符合一组标准的订阅列表怎么办。处理触发通知的系统将收到一个事件,并且需要查询一组与该事件相关的订阅。该事件不是基于用户的,因为多个用户可以拥有对此事件有效的订阅。我会在我的 UserRepository 上放置一个返回这些订阅的方法吗?还是我会创建一个 SubscriptionRepository?如果我创建 SubscriptionRepository,那不意味着 Subscription 也是一个聚合根吗?如果该问题的答案是肯定的,那么我的设计是否违反了 AggregateRoot 的概念,因为 User 和 Subscription 都包含对 Endpoint 实体的引用?

【问题讨论】:

    标签: c# domain-driven-design


    【解决方案1】:

    据我了解,只能从存储库中提取聚合根。

    这不太对。 repository 是持久性解决方案前面的抽象。您从记录簿中提取的任何状态都应来自存储库。

    聚合特定于您修改记录簿的用例 - 换句话说,当您进行写入时。

    如果您不打算更改任何内容,则无需(重新)检查聚合边界内的数据是否一致。视图、报告、分析——这些用例不需要聚合,因为它们不会产生任何需要保存在记录簿中的新状态。

    (CQRS:读取与写入的要求不同)。

    关键思想是只有聚合根应该保存在存储库中。

    因此,如果您有一个用例需要跨多个聚合读取Endpoints 状态的快照,那么请设计一个记录该要求的repository interface,并确保存储库不包含保存.

    【讨论】:

    • 好的,只要我的存储库只允许保存聚合根,我应该可以以只读方式检索任何子实体。改变那个孩子的唯一方法是通过一个聚合根来修改它,在我的例子中是一个用户。而且由于存储库只允许保存用户,所以我很安全。
    【解决方案2】:

    首先,我很困惑为什么您在用户和订阅中有端点?您可以删除 User 中的 Endpoints 还是没有意义?

    其次,问问自己

    如果我删除一个用户,我是否总是必须删除他的所有订阅和端点?

    如果答案是否定的,则用户不是聚合根。根据您的描述,我相信您错误地定义了聚合根。 如果你真的有一个 AR,你永远不需要一个单独的存储库来询问它的实体。它们仅通过 AR 调用并在其上下文中进行操作(过滤、更改等)。

    订阅可能是涉及用户并向其添加订阅的过程的一部分。也许 Subscription 是带有 Enpoints 的 AR。

    【讨论】:

    • 我域中的端点是电话号码、电子邮件地址等。我在用户中有端点,因为用户有电话号码和电子邮件地址。我在订阅中有端点,因为用户将订阅以将通知发送到他的电话号码或电子邮件地址。是的,当我删除一个用户时,所有这些用户的端点和订阅也会被删除。如果没有创建它们的用户,它们就无法存在。我希望检索用户及其所有端点和订阅,并且我希望检索一组与事件匹配的订阅。
    猜你喜欢
    • 1970-01-01
    • 2010-11-30
    • 2010-11-01
    • 1970-01-01
    • 2013-09-16
    • 2011-04-26
    • 1970-01-01
    相关资源
    最近更新 更多