OnionArch - 采用DDD+CQRS+.Net 7.0實現的洋蔥架構( 二 )

3.領域事件自動發布和保存在BaseDbContext文件的SaveChanges之前從實體中獲取領域事件并發布領域事件和保存領域事件通知,以備后查 。
//所有包含領域事件的領域跟實體var haveEventEntities = domainRootEntities.Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()).ToList();//所有的領域事件var domainEvents = haveEventEntities.SelectMany(x => x.Entity.DomainEvents).ToList();//根據領域事件生成領域事件通知var domainEventNotifications = new List<DomainEventNotification>();foreach (var domainEvent in domainEvents){domainEventNotifications.Add(new DomainEventNotification(nowTime, _currentUserService.UserId, domainEvent.EventType, JsonConvert.SerializeObject(domainEvent)));}//清除所有領域根實體的領域事件haveEventEntities.ForEach(entity => entity.Entity.ClearDomainEvents());//生成領域事件任務并執行var tasks = domainEvents.Select(async (domainEvent) =>{await _mediator.Publish(domainEvent);});await Task.WhenAll(tasks);//保存領域事件通知到數據表中DomainEventNotifications.AddRange(domainEventNotifications);領域事件發布和通知保存在底層實現 。開發人員不用關心領域事件發布和保存邏輯,只關注于領域事件的定義和處理即可 。
4.領域根實體審計信息自動記錄在BaseDbContext文件的Savechanges之前對記錄領域根實體的審計信息 。
//為每個繼承AggregateRootEntity領域跟的實體的AddedBy,Added,LastModifiedBy,LastModified賦值            //為刪除的實體生成實體刪除領域事件
DateTime nowTime = DateTime.UtcNow;var domainRootEntities = ChangeTracker.Entries<AggregateRootEntity>();foreach (var entry in domainRootEntities){switch (entry.State){case EntityState.Added:entry.Entity.AddedBy = _currentUserService.UserId;entry.Entity.Added = nowTime;break;case EntityState.Modified:entry.Entity.LastModifiedBy = _currentUserService.UserId;entry.Entity.LastModified = nowTime;break;case EntityState.Deleted:EntityDeletedDomainEvent entityDeletedDomainEvent = new EntityDeletedDomainEvent(_currentUserService.UserId,entry.Entity.GetType().Name,entry.Entity.Id,JsonConvert.SerializeObject(entry.Entity));entry.Entity.AddDomainEvent(entityDeletedDomainEvent);break;}}領域根實體審計信息記錄在底層實現 。開發人員不用關心審計字段的處理邏輯 。
5. 回收站式軟刪除采用回收站式軟刪除而不采用刪除字段的軟刪除方式,是為了避免垃圾數據和多次刪除造成的唯一索引問題 。自動生成和發布實體刪除的領域事件,代碼如上 。通過MediatR Handler,接收實體刪除領域事件,將已刪除的實體保存到回收站中 。
public class EntityDeletedDomainEventHandler : INotificationHandler<EntityDeletedDomainEvent>{private readonly RecycleDomainService _domainEventService;public EntityDeletedDomainEventHandler(RecycleDomainService domainEventService){_domainEventService = domainEventService;}public async Task Handle(EntityDeletedDomainEvent notification, CancellationToken cancellationToken){var eventData = JsonSerializer.Serialize(notification);RecycledEntity entity = new RecycledEntity(notification.OccurredOn, notification.OccurredBy, notification.EntityType, notification.EntityId, notification.EntityData);await _domainEventService.AddRecycledEntity(entity);}}6.CQRS(命令查詢分離)通過MediatR IRequest 實現了ICommand接口和Iquery接口,業務用例請求命令或者查詢繼承該接口即可 。
public interface ICommand : IRequest{}public interface ICommand<out TResult> : IRequest<TResult>{}public interface IQuery<out TResult> : IRequest<TResult>{}public class AddCategoryCommand : ICommand{public AddCategoryRequest Model { get; set; }}代碼中的AddCategoryCommand 增加類別命令繼承ICommand 。
7.自動工作單元Commit通過MediatR 管道實現了業務Command用例完成后自動Commit,開發人員不需要手動提交 。
public class UnitOfWorkProcessor<TRequest, TResponse> : IRequestPostProcessor<TRequest, TResponse> where TRequest : IRequest<TResponse>{private readonly IUnitOfWork _unitOfWork;public UnitOfWorkProcessor(IUnitOfWork unitOfWork){_unitOfWork = unitOfWork;}public async Task Process(TRequest request, TResponse response, CancellationToken cancellationToken){if (request is ICommand || request is ICommand<TResponse>){await _unitOfWork.CommitAsync();}}}

推薦閱讀