DDD实践:领域事件

目录(?)[+]

 

要求:修改good表,添加 organization

基础定义

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

Domain\SeedWork\Entity.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.Domain\Event\StockAddedToGoodsDomainEvent.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

要求:修改good表,添加 organization

基础定义

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

Domain\SeedWork\Entity.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.Domain\Event\StockAddedToGoodsDomainEvent.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

猜你喜欢

转载自www.cnblogs.com/webenh/p/11434783.html