zoukankan      html  css  js  c++  java
  • 关于ABP聚合根类AggregateRoot的思考

    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

  • 相关阅读:
    CAN总线(1)--初探(更新中)
    无约束时钟导致综合实现效果不一致
    推荐几本FPGA书籍(更新中)
    Ubuntu下配置支持Windows访问的Samba共享
    svn 节点处冲突 解决
    clock()、time()、clock_gettime()和gettimeofday()函数的用法和区别
    Linux入门,这七大习惯得有!
    Ubuntu硬盘空间不足时,添加硬盘的方法
    让你快速学会Shell脚本
    printf与fprintf函数的区别
  • 原文地址:https://www.cnblogs.com/sheepswallow/p/6272795.html
Copyright © 2011-2022 走看看