博主最近失业在家,找工作之余,自己动手写了个洋葱架构(整洁架构)解决方案,以总结和整理以前的项目经验,起名叫OnionArch,其目的是为了更好的实现采用DDD(领域驱动分析)和命令查询职责分离(CQRS)的洋葱架构 。
什么是OnionArchOnionArch解决方案清晰的展示了程序各分层的职责,帮助程序员写出逻辑更清晰的代码,提高程序的高内聚、低耦合性 。提高程序逻辑的可重用性,可扩展性和可测试性 。
OnionArch可降低单个微服务,特别是SAAS微服务开发的复杂度,在保证软件质量的基础上提高软件开发效率 。
OnionArch基于最新的开源.Net 7.0 RC1, 数据库采用PostgreSQL, 目前实现了包括多租户在内的12个特性 。详细内容请看:https://www.cnblogs.com/xiaozhuang/p/16772485.html
OnionArch如何实现更新指定字段的通用Handler本篇主要讲述OnionArch如何实现更新指定字段的通用Handler,这里的Handler是指MediatR中继承IRequestHandler接口的处理逻辑 。
Let me show you the code:
public async override Task<UpdateProductReply> UpdateProduct(UpdateProductRequest request, ServerCallContext context){UpdateCommand<UpdateProductRequest> updateProductCommand = new UpdateCommand<UpdateProductRequest>(Guid.Parse(request.ProductId),request,p => p.Description);await _mediator.Send(updateProductCommand);return new UpdateProductReply(){Message = "Update Product sucess"};}这是一个实现UpdateProduct业务用例的GRPC方法,新建一个UpdateCommand更新命令,并传入ProductId和要更新的数据request(表单提交的ViewModel),以及要更新的属性字段 。然后调用Mediator.Send发送该命令即可 。
UpdateCommand命令定义如下,继承自CQRS的ICommand接口,并采用了C#的record类型,确保必填字段不为空 。
public record UpdateCommand<TModel>(Guid Id, TModel Model, params Expression<Func<TModel, object>>[] UpdateProperties) : ICommand{ }第三个参数可以传入多个要更新的字段的Lambda 表达式,不采用字符串List的方式以防止程序员写错 。
Mediator的更新命令处理对象UpdateCommandHandler 接收到该命令进行处理:
public class UpdateCommandHandler<TModel, TEntity> : IRequestHandler<UpdateCommand<TModel>> where TEntity : BaseEntity{private readonly CURDDomainService<TEntity> _curdDomainService;public UpdateCommandHandler(CURDDomainService<TEntity> curdDomainService){_curdDomainService = curdDomainService;}public async Task<Unit> Handle(UpdateCommand<TModel> request, CancellationToken cancellationToken){TEntity updateEntity = await _curdDomainService.Retrieve(request.Id);updateEntity = request.Model.Adapt(updateEntity);List<string> updateProperties = new List<string>();foreach (var expression in request.UpdateProperties){var member = expression.Body as MemberExpression;if (member != null)updateProperties.Add(member.Member.Name);}await _curdDomainService.Update(updateEntity, updateProperties);return Unit.Value;}}首先根据传入的ProductId获取到Product实体,然和将传入的request Model数据,通过Mapster的Adapt方法赋值给该实体,该实体字段就有了最新的值 。
然后将传入的要更新的属性字段Lambda 表达式转换为属性字符串List,再调用领域层方法保存该实体到数据库 。
领域层更新实体的仓储方法如下:
public async Task<TEntity> Update(TEntity entity, IEnumerable<string> updateProperties){var entry = _dbContext.ChangeTracker.Entries<TEntity>().FirstOrDefault(p => p.Entity == entity);if (entry == null){entry = _dbContext.Set<TEntity>().Attach(entity);}entry.State = EntityState.Unchanged;foreach (var updateProperty in updateProperties){entry.Property(updateProperty).IsModified = true;}return entry.Entity;}可以看到,该方法只将要更新的字段设置为IsModified = true,即可达到更新特定字段的目的 。
经验总结扩展阅读
- 三伏天如何去除身体湿寒湿气 三伏天吃什么能去除湿气寒气
- 三伏天去寒气最好的方法 三伏天如何养生
- 染发剂用一半如何储存
- 如何免费去水印文件(最新去水印的方法)
- 刺激战场国际服如何下载(刺激战场国际服僵尸版下载)
- 白人饭营养高吗有没减重效果 如何看待白人饭的走红
- 手机进水怎么办,手机进水后怎么处理(手机进水了如何处理好)
- 花呗如何设置还款方式(花呗还款日期改到20号好不好)
- 火锅餐饮淡季如何引流
- 洪水后如何消毒