我正在构建一个通知系统,我的用户可以创建订阅,这些订阅定义了何时将通知传递给他们以及通过哪个端点。我已经确定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的概念,因为用户和订阅都包含对端点实体的引用?
答案 0 :(得分:1)
首先,它让我困惑为什么你在用户和订阅中有端点?你可以删除用户端点或没有意义吗?
其次,问问自己
如果删除用户,我是否总是要删除所有订阅和终端?
如果答案为否,则用户不是聚合根。根据您的描述,我相信您定义了您的聚合根错误。 如果你真的有一个AR,你就不需要一个对其实体有疑问的单独的存储库。它们仅在AR中被调用并在其上下文中被操纵(过滤,更改等)。
订阅可能是涉及用户并向其添加订阅的流程的一部分。订阅可能是带有Enpoints的AR。
答案 1 :(得分:1)
根据我的理解,只应从存储库中提取聚合根。
那不太对劲。 存储库是持久性解决方案前面的抽象。您从记录簿中提取的任何州都应通过存储库。
聚合特定于您正在修改记录簿的用例 - 换句话说,就是在您进行写入时。
如果您不打算进行任何更改,则无需(重新)检查聚合边界内的数据是否一致。视图,报告,分析 - 这些用例不需要聚合,因为它们不会产生任何需要在记录簿中保留的新状态。
(CQRS:读取的要求与写入不同)。
关键的想法是只有聚合根应该保存在存储库中。
因此,如果您的用例需要跨多个聚合读取Endpoints
状态的快照,那么设计一个记录该要求的repository interface,并确保存储库不存在不包括保存。