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

C# 在DDD/CQRS体系结构中处理伪聚合根,c#,mongodb,domain-driven-design,cqrs,C#,Mongodb,Domain Driven Design,Cqrs,我有以下课程: class AggregateRoot { // Defines common properties, Id, Version, etc. } class Container : AggregateRoot { public IEnumerable<User> Users { get; } public void AddUser(User newUser) { // ... } // ... } class User { p

我有以下课程:

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; }
}
class AggregateRoot
{
//定义通用属性、Id、版本等。
}
类容器:AggregateRoot
{
公共IEnumerable用户{get;}
public void AddUser(用户newUser)
{
// ...
}
// ...
}
类用户
{
公共无效添加通知(通知新建通知)
{
// ...
}
// ...
}
类通知
{
公共字符串消息{get;set;}
}
正如您所看到的,我有一个包含一个或多个用户的容器,每个用户可以向他们发送零个或多个通知

此场景中最常见的操作是添加新通知,因此我将经常检索用户。从容器中获取用户是可能的,但是我需要检索容器对象并在Users集合中搜索。如果容器很小而且是新的,这很好。但是随着容器的老化,它会有更多的用户。因此,用户集合可以变得相当大。我的问题是User类是一个伪聚合根,很多操作都是在用户身上完成的,但是用户不能存在于容器之外。使用存储用户的新存储库解决明显的性能问题带来了另一个问题。如何使用户存储库中的用户与容器中的用户保持同步

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

我正在使用MongoDb来存储事件

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

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

class User
{
  public int ContainerId { get; private set; }
  public void AddNotification() //...
}
容器类仍然可以提供与添加用户相关的一些行为。例如,它可以提供用于创建新用户的工厂方法,该方法将由实现用例的应用程序服务使用:

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);
  }
}
在此实现中,容器不存储用户集合。这是因为正如您所指出的,集合可能会变得非常大,因此无法在内存中进行管理。在MongoDB中,您将有一个容器集合和一个用户集合

每当您遇到“伪聚合根”的概念时,很可能有两个可能相关的聚合。这是解决这类问题的常用策略。关于这个主题的深入讨论,请看

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

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

class User
{
  public int ContainerId { get; private set; }
  public void AddNotification() //...
}
容器类仍然可以提供与添加用户相关的一些行为。例如,它可以提供用于创建新用户的工厂方法,该方法将由实现用例的应用程序服务使用:

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);
  }
}
在此实现中,容器不存储用户集合。这是因为正如您所指出的,集合可能会变得非常大,因此无法在内存中进行管理。在MongoDB中,您将有一个容器集合和一个用户集合


每当您遇到“伪聚合根”的概念时,很可能有两个可能相关的聚合。这是解决这类问题的常用策略。要深入了解该主题,请查看。

什么是“伪聚合根”?如果
User
不能存在于
容器
之外,那么
Container
听起来更有可能是您的聚合根。虽然像
Container
这样的泛型对我来说听起来不是普遍存在的语言。Oded:不是一个合适的聚合根,但它的行为就像聚合根一样。@AdrianThompsonPhillips:是的,容器名称不是真实的名称,但问题是相同的。也许我可以添加更多的解释…什么是“伪聚合根”?如果
User
不能存在于
Container
之外,那么
Container
听起来更有可能是您的聚合根。虽然像
Container
这样的泛型对我来说听起来不是普遍存在的语言。Oded:不是一个合适的聚合根,但它的行为就像聚合根一样。@AdrianThompsonPhillips:是的,容器名称不是真实的名称,但问题是相同的。也许我可以补充一些解释…“哦”我需要试试这个。谢谢!“哦”我要试试这个。谢谢!