AggregateRoot和Entity的區別 AggregateRoot繼承於Entity,並實現了IGeneratesDomainEvents介面 public class AggregateRoot : Entity, IAggregateRoot, IEntity, IGeneratesDo ...
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();
}
}
怎麼在聚合根裡面如何發佈領域事件
DomainEvents.Add(new BlogUrlChangedEventData(this, oldUrl));
沒有調用EventBus.Trigger來觸發領域事件,那添加到DomainEvents的EventData是在什麼時候觸發的呢?
閱讀下源碼不難發現,重寫了SaveChanges方法,在序列化到資料庫後觸發領域事件
聚合根裡面有兩個甚至多個方法都調用DomainEvents來產生領域事件,會不會造成事件多次觸發呢?
不會,閱讀源碼,很容易發現DomainEvents只是負責臨時傳遞EventData,傳遞給了changeReport這個局部變數後,就會清空,實際上真正觸發領域事件的是changeReport。
簡單說,就是每次調用SaveChanes後就會清空DomainEvents