DDD之EFCore发布领域事件的时机
# DDD之EFCore发布领域事件的时机
(1)在聚合根的实体对象的ChangeName()、构造方法等方法中立即发布领域事件,因为无论是应用服务还是领域服务,最终要调用聚合根中的方法来操作聚合,我们这样做可以确保领域事件不会被漏掉。
缺点:
- 存在重复发送领域事件的情况
- 领域事件发布的太早:在实体类的构造方法中发布领域事件,但是有可能因为数据验证没通过等原因,我们最终没有把这个新增的实体保存到数据库中,我们这样在构造方法中过早地发布领域事件就会导致“误报”
(2)把领域事件的发布延迟到上下文保存修改时。实体中只是注册要发布的领域事件,然后在上下文 的SaveChanges方法被调用时,我们再发布事件。
- 供聚合根进行事件注册的接口IDomainEvents,所有聚合根实体继承BaseEntity.cs
- 重写SaveChangesAsync
public override int SaveChanges(bool acceptAllChangesOnSuccess)
{
throw new NotImplementedException("Don not call SaveChanges, please call SaveChangesAsync instead.");
}
public async override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default)
{
var domainEntities = this.ChangeTracker.Entries<IDomainEvents>()
.Where(x => x.Entity.GetDomainEvents().Any());
var domainEvents = domainEntities
.SelectMany(x => x.Entity.GetDomainEvents()).ToList();
domainEntities.ToList()
.ForEach(entity => entity.Entity.ClearDomainEvents());
foreach (var domainEvent in domainEvents)
{
await mediator.Publish(domainEvent);
}
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
- 实体类改变的时候注册事件,SaveChangesAsync时会发布事件
- 执行添加接口的时候,事件注册后保存前发布,SaveChangesAsync会回滚失败