Domain driven design 我应该将存储库传递给引发事件的域方法吗

Domain driven design 我应该将存储库传递给引发事件的域方法吗,domain-driven-design,ddd-repositories,Domain Driven Design,Ddd Repositories,稍微相关:我是否应该将存储库传递给需要在方法操作发生并被持久化后触发事件的域对象方法 在这种情况下,系统需要在域对象的状态更改后发送的电子邮件。虽然不太可能,但状态更改可能不会持续,在这种情况下,不应发送电子邮件 我可以使用域服务来完成这项工作,但所有状态更改的逻辑都属于域对象,并且包含在域对象中,因此我的服务最终看起来像 StatusService(Irepo repo) { void ChangeStatus(domainObject myObject, status n

稍微相关:我是否应该将存储库传递给需要在方法操作发生并被持久化后触发事件的域对象方法

在这种情况下,系统需要在域对象的状态更改后发送的电子邮件。虽然不太可能,但状态更改可能不会持续,在这种情况下,不应发送电子邮件

我可以使用域服务来完成这项工作,但所有状态更改的逻辑都属于域对象,并且包含在域对象中,因此我的服务最终看起来像

 StatusService(Irepo repo) {

        void ChangeStatus(domainObject myObject, status newStatus) {
              try {
              myObject.ChangeStatus(newStatus);
              repo.Save(myObject);
              raiseEvent(new StausChangeEmailEvent(myObject))
              } catch { .. dont send email }
         }
有几个原因(其中一个原因是现在有两种改变状态的方法,只有一种发送电子邮件)

我想把它包装在域方法本身中,但这感觉也不对,因为我让域对象负责它自己的持久性。(尽管我认为我更喜欢它而不是域服务方式)

业务逻辑有点复杂,但我真正感兴趣的是如何仅在域对象被持久化之后触发事件


编辑:如果电子邮件无法发送,则这一点并不重要。如果状态不“接受”,则不发送电子邮件,这一点很重要,因为组织中的高级人员可能会在其邮箱中收到无效指示。

保持一致的交易行为会更好。您可以在同一事务(队列或数据库)中提交事件,并从那里进行调度。无论如何,如果这不是您想要的,您也可以让您的聚合记录事件,而不是让它直接引发事件。这允许您首先提交数据库事务,然后分派事件

public interface IRecordingAggRoot {
     IEnumerable<IEvent> RecordEvents();
}

_repository.Save(aggregate);
_tx.Commit();
_dispatcher.Dispatch(aggregate.RecordedEvents());
公共接口iRecordingRoot{
IEnumerable RecordEvents();
}
_保存(聚合);
_tx.Commit();
_dispatcher.Dispatch(aggregate.RecordedEvents());

您是否关心发送电子邮件是否失败?好问题-如果电子邮件部分失败,则不太重要。但是这种逻辑(提交;发送;)将在哪里运行?我越想它,我就越想“服务”——但在哪里:应用程序还是域服务?电子邮件是与状态更改操作相关的业务部门的一项强烈要求,但无法发送电子邮件(某种程度上)是可以接受的,这一事实让情况有点混乱。此外,如果我将其包装在一个调用domainModelObject上的changeStatus函数的应用程序服务中,那么开发人员可能会直接调用chageStatus,而不使用该服务来确保事件的正确顺序。(救援内部?)好吧,我现在明白了——花了一点时间才让硬币掉下来。域对象建立其记录事件的集合,应用层程序负责处理无错误提交()后的任何事件。我发现这篇文章也很有帮助
public interface IRecordingAggRoot {
     IEnumerable<IEvent> RecordEvents();
}

_repository.Save(aggregate);
_tx.Commit();
_dispatcher.Dispatch(aggregate.RecordedEvents());