C# 手动实现CQRS模式方法 C#如何不依赖MediatR实现CQRS
发布时间 - 2026-02-02 00:00:00 点击率:次CQRS在C#中最简手动实现是通过分离ICommand/IQuery接口及对应处理器,命令只改状态无返回,查询只读数据不修改,类型不可变且职责明确。
什么是CQRS在C#里最简可行的手动实现
CQRS(Command Query Responsibility Segregation)本质是把“改数据”和“读数据”彻底拆开——不是靠框架,而是靠接口分离、类型隔离和调用路径隔离。不依赖 MediatR 时,核心就是自己定义 ICommand / IQuery 接口,再配两个独立的处理器抽象,不共享输入/输出模型,也不共用执行管道。
手动定义命令与查询的接口和处理器
关键不是写得多,而是分得清。命令不返回业务数据(只返回 void 或 Task),查询不修改状态(方法体里不能有 SaveChanges、Update 等)。所有类型都应显式声明职责:
-
ICommandHandler:只接受一个TCommand,无返回值 -
IQueryHandler:接受TQuery,必须返回TResult - 命令和查询类型本身是
record或不可变class,不继承、不带行为
示例:
public record CreateOrderCommand(string CustomerId, decimal Amount); public interface ICommandHandler{ Task Handle(TCommand command); } public class CreateOrderCommandHandler : ICommandHandler { private readonly OrderDbContext _db; public CreateOrderCommandHandler(OrderDbContext db) => _db = db; public async Task Handle(CreateOrderCommand command) { var order = new Order { CustomerId = command.CustomerId, Amount = command.Amount }; await _db.Orders.AddAsync(order); await _db.SaveChangesAsync(); } }
如何避免手写大量 if-else 或 switch 路由逻辑
不用 MediatR 就意味着没有自动泛型解析,但也不必硬写反射调度。推荐两种轻量方案:
- DI 容器直接注册具体处理器,按需注入——比如在 Controller 里明确构造
CreateOrderCommandHandler,不追求“统一路由” - 若真需要统一入口(如 API 层只暴露一个
Dispatch()),可用Dictionary静态缓存已注册的处理器实例,首次访问时通过Activator.CreateInstance构建并缓存,后续直接Cast调用 - 切忌在调度层做运行时类型判断 + 反射调用——性能差、堆分配多、调试困难
注意:IServiceProvider.GetService(Type) 可用,但必须确保该 Type 已在 DI 中注册为具体实现,否则返回 null 不报错,容易漏测。
查询侧容易忽略的隔离细节
很多人只拆了命令,查询仍用 EF 的 DbSet 直接暴露给 API,这等于没 CQRS。真正隔离要体现在三处:
- 查询 DTO 必须和实体类物理分离(不同命名空间、不同程序集更佳),禁止
select new OrderDto()之外的任何对实体的引用 - 查询 Handler 内部应使用
AsNoTracking(),且不复用命令侧的DbContext实例(哪怕同一请求周期) - 避免在查询中调用
Include()加载深层导航——
那是命令侧或领域服务的事;查询应只投射所需字段,用
SELECT x,y,z级别控制
一个典型错误是:在 GetOrderSummaryQueryHandler 里调用了 _db.Orders.Include(x => x.Items),结果无意中触发了延迟加载或全表扫描——这不是 CQRS,这是披着查询外衣的命令副作用。
# 处理器
# ai
# switch
# 路由
# c#
# 延迟加载
# Object
# NULL
# if
# 命名空间
# select
# include
# void
# 继承
# 接口
# 堆
# class
# 泛型
# 这是
# 加载
# 也不
# 那是
# 首次
# 两种
# 很多人
# 所需
# 得多
# 这不是
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】
zabbix利用python脚本发送报警邮件的方法
BootStrap整体框架之基础布局组件
网页制作模板网站推荐,网页设计海报之类的素材哪里好?
Laravel中间件如何使用_Laravel自定义中间件实现权限控制
制作公司内部网站有哪些,内网如何建网站?
Laravel如何配置和使用缓存?(Redis代码示例)
原生JS实现图片轮播切换效果
Laravel项目如何进行性能优化_Laravel应用性能分析与优化技巧大全
如何快速搭建自助建站会员专属系统?
如何获取免费开源的自助建站系统源码?
Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解
如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程
米侠浏览器网页背景异常怎么办 米侠显示修复
如何自定义建站之星网站的导航菜单样式?
如何快速辨别茅台真假?关键步骤解析
Laravel路由怎么定义_Laravel核心路由系统完全入门指南
制作电商网页,电商供应链怎么做?
详解Android——蓝牙技术 带你实现终端间数据传输
EditPlus中的正则表达式实战(6)
网站图片在线制作软件,怎么在图片上做链接?
HTML 中动态设置元素 name 属性的正确语法详解
Laravel如何使用Service Provider注册服务_Laravel服务提供者配置与加载
Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】
香港服务器租用每月最低只需15元?
如何在万网自助建站中设置域名及备案?
Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性
LinuxShell函数封装方法_脚本复用设计思路【教程】
Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层
JavaScript实现Fly Bird小游戏
Windows Hello人脸识别突然无法使用
*服务器网站为何频现安全漏洞?
Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】
Laravel怎么实现一对多关联查询_Laravel Eloquent模型关系定义与预加载【实战】
做企业网站制作流程,企业网站制作基本流程有哪些?
Laravel事件监听器怎么写_Laravel Event和Listener使用教程
哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?
Win11搜索不到蓝牙耳机怎么办 Win11蓝牙驱动更新修复【详解】
如何在Tomcat中配置并部署网站项目?
如何快速生成ASP一键建站模板并优化安全性?
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤
如何快速生成专业多端适配建站电话?
Android使用GridView实现日历的简单功能
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Win11怎么修改DNS服务器 Win11设置DNS加速网络【指南】
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
Laravel如何生成和使用数据填充?(Seeder和Factory示例)
三星网站视频制作教程下载,三星w23网页如何全屏?
东莞专业网站制作公司有哪些,东莞招聘网站哪个好?


