首页
/ 告别SQL拼接烦恼:Dapper.SqlBuilder动态查询高效实现指南

告别SQL拼接烦恼:Dapper.SqlBuilder动态查询高效实现指南

2026-04-19 09:38:04作者:何将鹤

你是否曾为拼接动态SQL而编写大量条件判断?是否因字符串拼接导致代码难以维护?Dapper.SqlBuilder作为Dapper生态中的重要组件,提供了优雅的动态查询构建方案,让你摆脱繁琐的字符串操作,专注于业务逻辑实现。本文将带你从问题分析到实战应用,全面掌握这一工具的使用技巧。

认识动态查询的核心价值

在数据访问层开发中,查询条件的动态变化是常见需求。例如电商平台的商品筛选功能,用户可能会选择价格区间、品牌、评分等多种条件组合。传统字符串拼接方式不仅代码冗长,还存在SQL注入风险和维护困难等问题。

Dapper.SqlBuilder通过模板替换机制,将SQL片段与参数管理分离,实现了"搭积木"式的查询构建。这种方式带来三大核心价值:

  • 代码可读性提升:将查询逻辑分解为独立片段,结构清晰
  • 参数自动处理:内置参数化查询支持,杜绝SQL注入风险
  • 开发效率提高:链式API设计,减少重复代码

Dapper动态查询架构图

从零构建第一个动态查询

基础实现步骤

使用Dapper.SqlBuilder构建查询只需三个关键步骤:

// 1. 创建构建器实例并添加查询条件
var builder = new SqlBuilder()
    .Where("Status = @status", new { status = 1 })  // 基础条件
    .OrderBy("CreateTime DESC");  // 排序条件

// 2. 定义SQL模板,使用/**标记**/作为占位符
var template = builder.AddTemplate("SELECT * FROM Orders /**where**/ /**orderby**/");

// 3. 执行查询
using (var connection = new SqlConnection("你的连接字符串"))
{
    var orders = connection.Query<Order>(template.RawSql, template.Parameters);
}

上述代码会生成如下SQL: SELECT * FROM Orders WHERE Status = @status ORDER BY CreateTime DESC

动态条件处理

实际业务中,查询条件往往是动态变化的。以下是商品筛选的典型场景实现:

var builder = new SqlBuilder();
var template = builder.AddTemplate("SELECT * FROM Products /**where**/");

// 价格区间筛选
if (minPrice.HasValue)
    builder.Where("Price >= @minPrice", new { minPrice });  // 动态添加条件
    
if (maxPrice.HasValue)
    builder.Where("Price <= @maxPrice", new { maxPrice });  // 自动处理AND连接

// 分类筛选(支持多选)
if (categoryIds?.Any() == true)
    builder.Where("CategoryId IN @categoryIds", new { categoryIds });  // 数组参数自动处理

实战案例:多场景动态查询实现

场景一:分页查询实现

分页功能通常需要同时构建列表查询和总数查询,SqlBuilder支持多模板共享条件:

var builder = new SqlBuilder()
    .Where("IsDeleted = 0");  // 基础条件

// 列表查询模板
var listTemplate = builder.AddTemplate(@"
    SELECT * FROM (
        SELECT *, ROW_NUMBER() OVER (/**orderby**/) AS RowNum 
        FROM Users /**where**/
    ) t WHERE RowNum BETWEEN @Start AND @End", new { Start = 1, End = 20 });

// 总数查询模板
var countTemplate = builder.AddTemplate("SELECT COUNT(*) FROM Users /**where**/");

// 动态添加排序条件
builder.OrderBy("CreateTime DESC");

// 执行查询
var users = connection.Query<User>(listTemplate.RawSql, listTemplate.Parameters);
var total = connection.ExecuteScalar<int>(countTemplate.RawSql, countTemplate.Parameters);

场景二:复杂逻辑组合

处理OR条件时,SqlBuilder会自动将OR条件组合并添加括号,避免逻辑错误:

builder.Where("Role = 'Admin'")  // 基础条件
       .OrWhere("Department = @dept", new { dept = "IT" })  // OR条件1
       .OrWhere("Title LIKE @title", new { title = "%Manager%" });  // OR条件2

生成的WHERE子句为: WHERE Role = 'Admin' AND ( Department = @dept OR Title LIKE @title )

进阶技巧:提升动态查询效率

参数管理最佳实践

  1. 集中参数添加:通过AddParameters方法添加全局参数
builder.AddParameters(new { TenantId = currentTenantId })
       .Where("TenantId = @TenantId");  // 引用全局参数
  1. 强类型参数引用:使用nameof避免硬编码
var keyWord = "test";
builder.Where($"{nameof(Product.Name)} LIKE @{nameof(keyWord)}", new { keyWord });

避开三个常见陷阱

🔍 陷阱一:OrWhere逻辑组合 所有OrWhere条件会被合并为(A OR B OR C),与普通Where条件用AND连接

📊 陷阱二:模板标记冲突 避免自定义标记与SQL注释冲突,建议使用独特命名如/**custom_where**/

💡 陷阱三:重复添加问题 同一类型子句多次添加会自动合并,无需手动处理分隔符

技术对比:动态查询方案优劣势分析

方案 优点 缺点 适用场景
字符串拼接 灵活度高 易出错、有注入风险 简单查询、临时脚本
存储过程 数据库优化 维护困难、移植性差 复杂业务逻辑
EF LINQ 类型安全 性能开销、学习曲线 .NET全栈项目
Dapper.SqlBuilder 轻量高效、参数安全 需要模板标记 性能敏感的动态查询

学习资源导航

获取完整示例代码

要获取本文所有示例代码,可通过以下命令克隆项目:

git clone https://gitcode.com/gh_mirrors/dapper3/Dapper

通过Dapper.SqlBuilder,你可以用更优雅的方式处理动态查询,让数据访问层代码更清晰、更安全、更易于维护。无论是小型应用还是大型系统,这一工具都能为你的数据访问层带来显著改进。

登录后查看全文
热门项目推荐
相关项目推荐