1

OnionArch - 如何实现更新指定字段的通用Handler - 小庄

 1 year ago
source link: https://www.cnblogs.com/xiaozhuang/p/16779546.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

博主最近失业在家,找工作之余,自己动手写了个洋葱架构(整洁架构)解决方案,以总结和整理以前的项目经验,起名叫OnionArch,其目的是为了更好的实现采用DDD(领域驱动分析)和命令查询职责分离(CQRS)的洋葱架构。

什么是OnionArch

OnionArch解决方案清晰的展示了程序各分层的职责,帮助程序员写出逻辑更清晰的代码,提高程序的高内聚、低耦合性。提高程序逻辑的可重用性,可扩展性和可测试性。

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,即可达到更新特定字段的目的。

输出的SQL语句如下:

Executed DbCommand (11ms) [Parameters=[@p3='?' (DbType = Guid), @p0='?', @p1='?' (DbType = DateTime), @p2='?'], CommandType='Text', CommandTimeout='30']
      UPDATE "T_Product" SET "Description" = @p0, "LastModified" = @p1, "LastModifiedBy" = @p2
      WHERE "Id" = @p3;

可以看到,SQL只更新了Description字段,LastModified和LastModifiedBy字段是OnionArch的实体数据审计特性自动加上的。打完收工。

找工作时间

接下来又到了找工作广告时间:

▪ 博主有15年以上的软件技术实施经验(Technical Leader),专注于微服务和云原生(K8s)软件架构设计、专注于 .Net Core\Java开发和Devops构建发布。
▪ 博主10年以上的软件交付管理经验(Project Manager & Product Ower),致力于敏捷(Scrum)项目管理、软件产品业务需求分析和原型设计。
▪ 博主熟练配置和使用 Microsoft Azure云。
▪ 博主为人诚恳,积极乐观,工作认真负责。 

我家在广州,也可以去深圳工作。做架构和项目管理都可以,希望能从事稳定行业的业务数字化转型。有工作机会推荐的朋友可以加我微信 15920128707,微信名字叫Jerry。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK