惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
博客园 - Franky
罗磊的独立博客
G
Google Developers Blog
The GitHub Blog
The GitHub Blog
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
V
V2EX
F
Fortinet All Blogs
阮一峰的网络日志
阮一峰的网络日志
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
U
Unit 42
GbyAI
GbyAI
A
About on SuperTechFans
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
雷峰网
雷峰网
Microsoft Azure Blog
Microsoft Azure Blog
Martin Fowler
Martin Fowler
D
DataBreaches.Net
The Cloudflare Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MongoDB | Blog
MongoDB | Blog

博客园 - 小庄

如何正确的 DDD AI时代的领域驱动设计:DAD 我开发了个人工智能应用, 请大家给点意见 通过代理使用人工智能服务保姆级教程 OnionArch 2.0 - 基于DDD的洋葱架构改进版开源 根据MediatR的Contract Messages自动生成Minimal WebApi接口 MediatRPC - 基于MediatR和Quic通讯实现的RPC示例,新增Server Stream功能,发布开源地址。 MediatRPC - 基于MediatR和Quic通讯实现的RPC框架,比GRPC更简洁更低耦合,开源发布第一版 Dapr实现.Net Grpc服务之间的发布和订阅,并采用WebApi类似的事件订阅方式 关于.Net 7.0 RC gRPC JSON 转码为 Swagger/OpenAPI文档的注意事项 OnionArch - 采用DDD+CQRS+.Net 7.0实现的洋葱架构 Blazor+Dapr+K8s微服务之基于WSL安装K8s集群并部署微服务 Blazor+Dapr+K8s微服务之事件发布订阅 Blazor+Dapr+K8s微服务之状态管理 Blazor+Dapr+K8s微服务之开发环境调试 Blazor+Dapr+K8s微服务之服务调用 .Net Core 通过依赖注入和动态加载程序集实现宿主程序和接口实现类库完全解构 面向对象之"三段论" 使用WIX打包客户端程序
OnionArch - 如何实现更新指定字段的通用Handler
小庄 · 2022-10-11 · via 博客园 - 小庄

博主最近失业在家,找工作之余,自己动手写了个洋葱架构(整洁架构)解决方案,以总结和整理以前的项目经验,起名叫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。