AggregateRoot和Entity的区别
AggregateRoot继承于Entity,并实现了IGeneratesDomainEvents接口
public class AggregateRoot<TPrimaryKey> : Entity<TPrimaryKey>, IAggregateRoot<TPrimaryKey>, IEntity<TPrimaryKey>, IGeneratesDomainEvents{ public AggregateRoot(); [NotMapped] public virtual ICollection<IEventData> DomainEvents { get; }}
在DDD里面聚合根是一定对应一个实体
为什么要使用AggregateRoot
实现了IGeneratesDomainEvents,属性DomainEvents可以方便产生领域事件,这些事件在当前的工作单元完成之前自动的触发。
在ABP里面不会强迫使用聚合,但既然选用了ABP这个框架,那就是希望能使用DDD的开发模式,所以使用AggregateRoot是更好的实践。
IGeneratesDomainEvents解析
先贴关键源码
public abstract class AbpDbContext : DbContext, ITransientDependency{ public override int SaveChanges() { //从DomainEvents中拿到定义的领域事件 var changeReport = ApplyAbpConcepts(); var result = base.SaveChanges(); //数据保存后,触发领域事件 EntityChangeEventHelper.TriggerEvents(changeReport); return result; } protected virtual EntityChangeReport ApplyAbpConcepts() { var changeReport = new EntityChangeReport(); ... var entries = ChangeTracker.Entries().ToList(); foreach (var entry in entries) { ... AddDomainEvents(changeReport.DomainEvents, entry.Entity); } return changeReport; } protected virtual void AddDomainEvents(List<DomainEventEntry> domainEvents, object entityAsObj) { var generatesDomainEventsEntity = entityAsObj as IGeneratesDomainEvents; if (generatesDomainEventsEntity == null) { return; } if (generatesDomainEventsEntity.DomainEvents.IsNullOrEmpty()) { return; } domainEvents.AddRange(generatesDomainEventsEntity.DomainEvents.Select(eventData => new DomainEventEntry(entityAsObj, eventData))); //清空DomainEvents generatesDomainEventsEntity.DomainEvents.Clear(); }}
1.在保存后
怎么在聚合根里面如何发布领域事件
DomainEvents.Add(new BlogUrlChangedEventData(this, oldUrl));
没有调用EventBus.Trigger来触发领域事件,那添加到DomainEvents的EventData是在什么时候触发的呢?
阅读下源码不难发现,重写了SaveChanges方法,在序列化到数据库后触发领域事件
聚合根里面有两个甚至多个方法都调用DomainEvents来产生领域事件,会不会造成事件多次触发呢?
不会,阅读源码,很容易发现DomainEvents只是负责临时传递EventData,传递给了changeReport这个局部变量后,就会清空,实际上真正触发领域事件的是changeReport。
简单说,就是每次调用SaveChanes后就会清空DomainEvents
- 热点聚合:AggregateRoot 聚合 思考 关于 ABP