在DDD/CQRS体系结构中处理伪聚合根



我有以下类:

class AggregateRoot
{
// Defines common properties, Id, Version, etc.
}
class Container : AggregateRoot
{
public IEnumerable<User> Users { get; }
public void AddUser(User newUser)
{
// ...
}
// ...
}
class User
{
public void AddNotification(Notification newNotification)
{
// ...
}
// ...
}
class Notification
{
public string Message { get; set; }
}

正如你所看到的,我有一个容器,其中包含一个或多个用户,每个用户可以向他们发送零个或更多通知。

在这种情况下,最常见的操作是添加新的通知,因此我将经常检索用户。从Container中获取User是可能的,但随后我需要检索Container对象并在Users集合中进行搜索。如果集装箱很小,而且是新的,那也没关系。但是随着容器的老化,它会得到更多的用户。因此,用户集合可能会变得相当大。我的问题是,User类是一个伪聚合根,在User上做了很多操作,但User不能存在于Container之外。使用存储用户的新存储库解决明显的性能问题会带来另一个问题。如何使用户存储库中的用户与容器中的用户保持同步?

我可以在Container类中只存储用户ID,但这会占用向Container添加新用户的业务逻辑,因为我无法再查找某些属性。那么,我该怎么做呢?

我正在使用MongoDb来存储事件。

使用新的存储库解决明显的性能问题用户提出了另一个问题。如何将用户保留在用户中存储库是否与容器中的用户同步?

您可以以稍微不同的方式实现该模型。如果Container上的唯一行为是添加User实例,那么您也可以使User成为聚合。为了表达用户必须是容器一部分的约束,用户可以通过ID引用容器。

class User
{
public int ContainerId { get; private set; }
public void AddNotification() //...
}

Container类仍然可以提供一些与添加用户相关联的行为。例如,它可以提供一种创建新用户的工厂方法,该方法将由实现用例的应用程序服务使用:

class Container
{
public int Id { get; private set; }
public User CreateUser(string userName)
{
return new User(this.Id, userName);
}
}
class UserAppService
{
public void AddUserToContainer(int containerId, string userName)
{
var container = this.containerRepository.Get(containerId);    
var user = container.CreateUser(userName);    
this.userRepository.Add(user);
}
}

在这个实现中,Container不存储用户的集合。这是因为正如您所指出的,集合可能会变得非常大,因此无法在内存中进行管理。在MongoDB中,您将拥有一个容器集合和一个用户集合。

每当你遇到"伪聚合根"的概念时,很可能你有两个可能相关的聚合。这是解决这类问题的常用策略。要深入了解这一主题,请参阅Vaughn Vernon的《有效骨料设计》。

最新更新