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();}}}
推荐阅读
- 我的 Kafka 旅程 - Consumer
- 最早人工呼吸救人的医学家是谁 最早采用人工呼吸的医学家是谁
- 宝马gtsuv是什么意思
- 电磁炉插电没开有辐射吗?
- 转炉煤气回收一般采用什么方法
- 合理安排工作时间,提高工作效率 采用工作时间记录法提高工作效率
- 贴梗海棠怎样繁殖,一般采用分株繁殖、压条繁殖、插扦繁殖
- 羽衣甘蓝栽培要点
- 名爵是国产还是合资车品牌 名爵是国产还是合资车?
- 品胜易充如何输出2a