域驱动设计中的存储库和聚合根

时间:2017-04-12 06:34:36

标签: c# domain-driven-design

我正在构建一个通知系统,我的用户可以创建订阅,这些订阅定义了何时将通知传递给他们以及通过哪个端点。我已经确定User是一个Aggregate Root,并且将为它们提供一个Repository。尽管如此,我在围绕这个概念时遇到了一些麻烦。根据我的理解,只应从存储库中提取聚合根。

假设我有一个用户

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

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

我的订阅还包含对端点的引用,因为此订阅需要知道在何处传递。

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

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

2 个答案:

答案 0 :(得分:1)

首先,它让我困惑为什么你在用户和订阅中有端点?你可以删除用户端点或没有意义吗?

其次,问问自己

  

如果删除用户,我是否总是要删除所有订阅和终端?

如果答案为否,则用户不是聚合根。根据您的描述,我相信您定义了您的聚合根错误。 如果你真的有一个AR,你就不需要一个对其实体有疑问的单独的存储库。它们仅在AR中被调用并在其上下文中被操纵(过滤,更改等)。

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

答案 1 :(得分:1)

  

根据我的理解,只应从存储库中提取聚合根。

那不太对劲。 存储库是持久性解决方案前面的抽象。您从记录簿中提取的任何州都应通过存储库。

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

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

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

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

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