Dapper 结合 MediatR 实现 CQRS 的本质是将读写逻辑剥离至职责清晰的 Handler:Dapper 以轻量高效方式执行原生 SQL,适配命令侧事务与查询侧性能需求,MediatR 通过管道行为统一处理日志、校验与异常,三层结构明确分离关注点。
用 Dapper 结合 MediatR 实现 CQRS,本质是把“写逻辑”和“读逻辑”从 API 层剥离,交给职责清晰的 Handler 去执行,而 Dapper 负责高效、可控地操作数据库。它不依赖复杂 ORM 的抽象,又比裸 ADO.NET 更简洁——刚好匹配 CQRS 对读写分离、轻量可控的要求。
命令操作关注数据变更、事务、业务校验。Dapper 的 Execute 方法天然适配这类场景,返回影响行数可直接用于结果判断。
IRequestHandler 中,用 Dapper 执行 INSERT/UPDATE/DELETE SQLconnection.BeginTransaction() 包裹多个 Dapper 操作,确保一致性conn.Execute("UPDATE Bookings SET Status = @Status WHERE Id = @Id", new { Status = "Reserved", Id = cmd.Id })
查询只读、高频、强调性能与灵活性。Dapper 的 Query 系列方法(Query、QueryFirst、QuerySingle、QueryMultiple)配合原生 SQL,能精准控制执行计划和映射行为。
IRequestHandler,内部用 Dapper.QueryAsyncQueryMultiple 一次性拉取主子表数据,再手动组装 DTO,省去 N+1 和 EF 的延迟加载开销MediatR 的管道行为(Pipeline Behavior)不是装饰器,而是对所有请求统一拦截的“横切点”。Dapper 本身不提供日志或异常包装,但借助 Behavior 就能低成本补全。
代码怎么放,直接影响可维护性。CQRS 不是加一堆文件夹,而是让每层意图一目了然。
Application.Bookings.Commands.ReserveBookingCommand 和 Application.Bookings.Queries.GetBookingQuery
IDbConnectionFactory)services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));,Handler 类必须 public 且实现对应泛型接口基本上就这些。Dapper 提供肌肉,MediatR 提供神经,CQRS 提供骨架——三者合起来,不是堆技术,而是让每次数据库操作都目的明确、路径清晰、问题好追。