zoukankan      html  css  js  c++  java
  • DDD实践:领域事件

    目录(?)[+]

     

    要求:修改good表,添加 organization

    基础定义

    用于引发和调度事件的延迟方法 AddDomainEvent

    DomainSeedWorkEntity.cs

    public abstract class Entity<T>
        {
            int? _requestedHashCode;
            T _Id;        
            public virtual  T Id 
            {
                get
                {
                    return _Id;
                }
                protected set
                {
                    _Id = value;
                }
            }
    
            private List<INotification> _domainEvents;
            public IReadOnlyCollection<INotification> DomainEvents => _domainEvents?.AsReadOnly();
    
            public void AddDomainEvent(INotification eventItem)
            {
                _domainEvents = _domainEvents ?? new List<INotification>();
                _domainEvents.Add(eventItem);
            }
    
            public void RemoveDomainEvent(INotification eventItem)
            {
                _domainEvents?.Remove(eventItem);
            }
    
            public void ClearDomainEvents()
            {
                _domainEvents?.Clear();
            }
    
            public bool IsTransient()
            {
                return Id.ToString() == default(T).ToString();
            }
    
            public override bool Equals(object obj)
            {
                if (obj == null || !(obj is Entity<T>))
                    return false;
    
                if (Object.ReferenceEquals(this, obj))
                    return true;
    
                if (this.GetType() != obj.GetType())
                    return false;
    
                Entity<T> item = (Entity<T>)obj;
    
                if (item.IsTransient() || this.IsTransient())
                    return false;
                else
                    return item.Id.ToString() == this.Id.ToString();
            }
    
            public override int GetHashCode()
            {
                if (!IsTransient())
                {
                    if (!_requestedHashCode.HasValue)
                        _requestedHashCode = this.Id.GetHashCode() ^ 31; // XOR for random distribution (http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx)
    
                    return _requestedHashCode.Value;
                }
                else
                    return base.GetHashCode();
    
            }
            public static bool operator ==(Entity<T> left, Entity<T> right)
            {
                if (Object.Equals(left, null))
                    return (Object.Equals(right, null)) ? true : false;
                else
                    return left.Equals(right);
            }
    
            public static bool operator !=(Entity<T> left, Entity<T> right)
            {
                return !(left == right);
            }
        }

    聚合根

    Goods.cs

      public class Goods: Entity<Guid>, IAggregateRoot
        {
            
            public string CreatedBy { get; private set; }
            public DateTime? CreatedTime { get; private set; }
    
            public string ModifiedBy { get; private set; }
    
            public DateTime? ModifiedTime { get; private set; }
    
            public string GoodsName { get; private set; }
            public int? GoodsNum { get; private set; }
    
    
    
            public Goods(string createdBy, DateTime? createdTime, string modifiedBy, DateTime? modifiedTime, string goodsName, int? goodsNum)
            {
                CreatedBy = createdBy;
                CreatedTime = createdTime;
                ModifiedBy = modifiedBy;
                ModifiedTime = modifiedTime;
                GoodsName = goodsName;
                GoodsNum = goodsNum;
            }
    
            public void StockAddedToGoods()
            {
                AddDomainEvent(new StockAddedToGoodsDomainEvent());  //加入事件列表
            }
    
    
            public void SetModified()
            {
                ModifiedBy = "aaaaa";
                ModifiedTime = DateTime.Now;
            }
        }

    请注意 AddDomainEvent 方法的唯一功能是将事件添加到列表。 尚未调度任何事件,尚未调用任何事件处理程序。
    你需要在稍后将事务提交到数据库时调度事件。 如果使用 Entity Framework Core,意味着在 EF DbContext 的 SaveChanges 方法中,如以下示例所示:

    // EF Core DbContext
    public class SampleContext : DbContext, IUnitOfWork
    {
        // ...
        public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            // Dispatch Domain Events collection.
            // Choices:
            // A) Right BEFORE committing data (EF SaveChanges) into the DB. This makes
            // a single transaction including side effects from the domain event
            // handlers that are using the same DbContext with Scope lifetime
            // B) Right AFTER committing data (EF SaveChanges) into the DB. This makes
            // multiple transactions. You will need to handle eventual consistency and
            // compensatory actions in case of failures.        
            await _mediator.DispatchDomainEventsAsync(this);
    
            // After this line runs, all the changes (from the Command Handler and Domain
            // event handlers) performed through the DbContext will be committed
            var result = await base.SaveChangesAsync();
        }

    }

    Organization.cs

        public class Organization: 
            Entity<Guid>, IAggregateRoot
        {
            public string CreatedBy { get; set; }
            public DateTime CreatedTime { get; set; }
            public string ModifiedBy { get; set; }
            public DateTime ModifiedTime { get; set; }
    
            public string Name { get; set; }
    
            private Organization() { }
    
            public Organization(Guid id, string name, string createdBy, DateTime createdTime, string modifiedBy,DateTime modifiedTime)
            {
                Id = id;
                Name = name;
                CreatedBy = createdBy;
                ModifiedBy = modifiedBy;
                ModifiedTime = modifiedTime;
    
                AddDomainEvent(new OrganizationCreatedDomainEvent(name, id));
            }
    
        }

    CQRS

    1.创建命令

        [DataContract]
        public class UpdateGoodsAndAddStockCommand : IRequest<bool>
        {
            [DataMember]
            public Guid Id { get; set; }
            [DataMember]
            public string CreatedBy { get; private set; }
    
            [DataMember]
            public string GoodsName { get; private set; }
            [DataMember]
            public int GoodsNum { get; private set; }
        }

    2.创建处理

        public class UpdateGoodsAndAddStockCommandHandler: IRequestHandler<UpdateGoodsAndAddStockCommand, bool>
        {
            private readonly IGoodsRepository _goodsRepository;
            private readonly IMediator _mediator;
    
            public UpdateGoodsAndAddStockCommandHandler(IGoodsRepository goodsRepository, IMediator mediator)
            {
                _goodsRepository = goodsRepository;
                _mediator = mediator;
            }
    
    
            public async Task<bool> Handle(UpdateGoodsAndAddStockCommand request, CancellationToken cancellationToken)
            {
                var good = await _goodsRepository.GetAsync(request.Id);
    
                
                good.SetModified(); //赋值修改人和修改时间,
                good.StockAddedToGoods(); //添加 Stock 事件
                  return await _goodsRepository.UnitOfWork.SaveEntitiesAsync();
            }
        }

    3.使用 IoC 的域事件调度程序

    public class MediatorModule : Autofac.Module
        {
            protected override void Load(ContainerBuilder builder)
            {
                builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly)
                    .AsImplementedInterfaces();
    
                // Register all the Command classes (they implement IRequestHandler) in assembly holding the Commands
                builder.RegisterAssemblyTypes(typeof(CreateOrderCommand).GetTypeInfo().Assembly)
                    .AsClosedTypesOf(typeof(IRequestHandler<,>));
    
               //这里
    builder.RegisterAssemblyTypes(typeof(UpdateGoodsAndAddStockCommand).GetTypeInfo().Assembly)
               .AsClosedTypesOf(typeof(IRequestHandler<,>))
     
            // Other registrations ...
        }
    }                          

    事件列表

    Sample.DomainEventStockAddedToGoodsDomainEvent.cs

       public class StockAddedToGoodsDomainEvent: INotification
        {
            public Organization Organization { get; }
    
    
            public StockAddedToGoodsDomainEvent()
            {
                Organization = new Organization(Guid.NewGuid(), "tss","tss", DateTime.Now,null,DateTime.Now);
            }
        }

    事件处理:StockAddedToGoodsDomainEventHandler

        public class StockAddedToGoodsDomainEventHandler : INotificationHandler<StockAddedToGoodsDomainEvent>
        {
            private readonly IOrganizationRepository _iorganizationRepository;
            private readonly ILoggerFactory _logger;
            private readonly ISampleIntegrationEventService _sampleIntegrationEventService;
    
            public StockAddedToGoodsDomainEventHandler(IOrganizationRepository iorganizationRepository, ILoggerFactory logger)
            {
                _iorganizationRepository = iorganizationRepository;
                _logger = logger;
            }
    
            public async Task Handle(Domain.Events.StockAddedToGoodsDomainEvent notification, CancellationToken cancellationToken)
            {
                _iorganizationRepository.Add(notification.Organization);
    
                var organization = await _iorganizationRepository.GetAsync(notification.Organization.Id);
                await _iorganizationRepository.UnitOfWork.SaveEntitiesAsync();
                _logger.CreateLogger(nameof(StockAddedToGoodsDomainEventHandler))
                 .LogTrace($"Stock with Id: {organization.Id} has been successfully Created");
            }
        }

    资料:

    microsoft.doc 域事件:设计和实现
    微软的官方.NET CORE微服务示例eShopOnContainers

  • 相关阅读:
    Python Scrapy 爬虫入门
    Python Requests 高级用法
    Python Requests库快速入门
    linux 高并发事件触发处理 — epoll
    初识Python爬妹子图片
    android 使用gradle实现资源自动拷贝
    Android Studio Cmake使用 (附带demo)
    JNI 学习笔记
    Cmake 常见命令说明
    mybatis逆向工程生成代码
  • 原文地址:https://www.cnblogs.com/webenh/p/11434783.html
Copyright © 2011-2022 走看看