Domain driven design 如果使用域事件,我应该使用存储库模式添加项还是创建事件?

Domain driven design 如果使用域事件,我应该使用存储库模式添加项还是创建事件?,domain-driven-design,repository-pattern,ddd-repositories,domain-events,Domain Driven Design,Repository Pattern,Ddd Repositories,Domain Events,我试图理解在特定情况下添加新域实体的方法 现在,我通常会创建实体,然后通过存储库添加它们。我想我还是会这么做 我的例子是我们通常向系统添加资产。像这样: var asset= new Asset(); /*bunch of prop setting*/ _assetRepository.Add(asset); 然而,资产创建是我们希望遵循特定流程的一个事件。因此,开发人员建议我们不再需要这样做,因为它可以由域事件处理: var asset= new Asset(); /*bunch

我试图理解在特定情况下添加新域实体的方法

现在,我通常会创建实体,然后通过存储库添加它们。我想我还是会这么做

我的例子是我们通常向系统添加资产。像这样:

 var asset= new Asset();
/*bunch of prop setting*/
 _assetRepository.Add(asset);
然而,资产创建是我们希望遵循特定流程的一个事件。因此,开发人员建议我们不再需要这样做,因为它可以由域事件处理:

var asset= new Asset();
   /*bunch of prop setting*/
asset.Create(location);
现在,create方法将引发一个事件,并由create事件处理程序进行处理,该处理程序基本上只是将其插入到repo中,并执行一些其他操作,例如向创建位置的仓库经理发送电子邮件等

然而,在我看来,在资产上有一个create事件看起来相当活跃。然而,在该领域,人们谈论正在创建的新资产。所以我们不确定


想法?

创建的域事件应该在
资产
类的构造函数中引发,因为这是创建特定实体的时间。在当前实现中,这是错误的,因为资产实体提供了无参数构造函数。相反,创建一个构造函数,该构造函数将所有必需的属性作为参数,从而防止在不一致的状态下创建资产实体。它可能是这样的:

public class Asset
{
  public Asset(string prop1, decimal prop2) 
  {
    this.Prop1 = prop1;
    this.Prop2 = prop2;
    DomainEvents.Raise(new AssetCreated(prop1, prop2));
  }

  public string Id { get; private set; }
  public string Prop1 { get; private set; }
  public decimal Prop2 { get; private set; }
}

创建实体后,仍然需要使用存储库来持久化实体。这可能会有问题,因为
AssetCreated
的处理程序无法引用其ID,因为在收到通知时尚未分配该ID。如果使用事件源,则创建事件将显式存储在基础事件存储中

创建的域事件应该在
资产
类的构造函数中引发,因为这是创建特定实体的时间。在当前实现中,这是错误的,因为资产实体提供了无参数构造函数。相反,创建一个构造函数,该构造函数将所有必需的属性作为参数,从而防止在不一致的状态下创建资产实体。它可能是这样的:

public class Asset
{
  public Asset(string prop1, decimal prop2) 
  {
    this.Prop1 = prop1;
    this.Prop2 = prop2;
    DomainEvents.Raise(new AssetCreated(prop1, prop2));
  }

  public string Id { get; private set; }
  public string Prop1 { get; private set; }
  public decimal Prop2 { get; private set; }
}

创建实体后,仍然需要使用存储库来持久化实体。这可能会有问题,因为
AssetCreated
的处理程序无法引用其ID,因为在收到通知时尚未分配该ID。如果使用事件源,则创建事件将显式存储在基础事件存储中

我为这个问题奋斗了很长时间。但没有好的解决办法。我想,

  • 在域事件所属的聚合成功持久化之前,不应发布或处理域事件
  • 发布任何事件不是应用层的责任

到目前为止,我认为最好的方法是利用AOP。我们可以在聚合中“激发”事件,但我们不是立即分派它们,而是将其保留在队列中,并在相应的事务成功后真正分派它
我们可以定义一个定制的@Transactional拦截器来实现这一点,从而使应用程序服务不知道任何“事件发布”的概念。

我为这个问题奋斗了相当长的时间。但没有好的解决办法。我想,

  • 在域事件所属的聚合成功持久化之前,不应发布或处理域事件
  • 发布任何事件不是应用层的责任

到目前为止,我认为最好的方法是利用AOP。我们可以在聚合中“激发”事件,但我们不是立即分派它们,而是将其保留在队列中,并在相应的事务成功后真正分派它
我们可以定义一个定制的@Transactional拦截器来实现这一点,从而防止应用程序服务知道任何“事件发布”的概念。

好的,我认为这是有意义的。但是,正如您所说,我的问题是在不知道AssetId的情况下(它是一个标识)(没有自然密钥),在引发create事件时,我将无法访问它。因此,我如何在提出的电子邮件等中引用资产。我想我必须想办法将其重新绑定在一起。一种方法是为资产使用Guid。另一件需要注意的事情是,无论您对该事件做什么,都必须是事务性的,因为如果由于某种原因创建或更新的实体没有持久化,则域事件处理程序执行的所有操作都不再有效。我在想guid。是的,可能需要在队列中添加一些东西,然后在事务失败/未完成时将它们拉出来。好的,我认为这是有道理的。但是,正如您所说,我的问题是在不知道AssetId的情况下(它是一个标识)(没有自然密钥),在引发create事件时,我将无法访问它。因此,我如何在提出的电子邮件等中引用资产。我想我必须想办法将其重新绑定在一起。一种方法是为资产使用Guid。另一件需要注意的事情是,无论您对该事件做什么,都必须是事务性的,因为如果由于某种原因创建或更新的实体没有持久化,则域事件处理程序执行的所有操作都不再有效。我在想guid。是的,可能需要在队列中添加一些东西,然后在事务失败/未完成时将其拉入