告别SQL拼接噩梦:Dapper.SqlBuilder动态查询实战指南
【免费下载链接】Dapper 项目地址: https://gitcode.com/gh_mirrors/dapper3/Dapper
在数据访问层开发中,你是否还在手写冗长的条件判断来拼接SQL?是否因参数化查询处理不当导致安全隐患?Dapper.SqlBuilder组件提供了优雅的解决方案,让动态查询构建如同搭积木般简单。本文将通过实战案例,带你掌握从基础查询到复杂筛选器的实现技巧,彻底摆脱字符串拼接的困扰。
核心组件与工作原理
Dapper.SqlBuilder位于Dapper.SqlBuilder/SqlBuilder.cs,其核心设计采用模板替换机制,通过/**标记**/占位符动态注入SQL片段。主要包含两大核心类:
- SqlBuilder:负责管理查询片段(Where/OrderBy等)和参数集合,提供链式API构建查询逻辑
- Template:处理SQL模板渲染,自动合并参数并生成最终可执行SQL
基础架构解析
SqlBuilder内部通过字典维护不同类型的查询子句,关键代码如下:
private readonly Dictionary<string, Clauses> _data = new Dictionary<string, Clauses>();
protected SqlBuilder AddClause(string name, string sql, object parameters,
string joiner, string prefix = "", string postfix = "", bool isInclusive = false)
{
if (!_data.TryGetValue(name, out var clauses))
{
clauses = new Clauses(joiner, prefix, postfix);
_data[name] = clauses;
}
clauses.Add(new Clause(sql, parameters, isInclusive));
_seq++;
return this;
}
当调用Where()或OrderBy()等方法时,实际上是向对应Clause集合添加SQL片段,最终由Clauses类负责按规则拼接(如Where子句默认使用AND连接)。
快速上手:从静态查询到动态构建
基础查询构建
使用SqlBuilder构建简单查询仅需三步:
- 创建SqlBuilder实例并添加查询条件
- 使用AddTemplate定义SQL模板
- 执行渲染并获取结果
var builder = new SqlBuilder()
.Where("Status = @status", new { status = 1 })
.OrderBy("CreateTime DESC");
var template = builder.AddTemplate("SELECT * FROM Orders /**where**/ /**orderby**/");
// 最终生成: SELECT * FROM Orders WHERE Status = @status ORDER BY CreateTime DESC
using (var connection = new SqlConnection("..."))
{
var orders = connection.Query<Order>(template.RawSql, template.Parameters);
}
动态条件筛选
业务场景中常需根据不同条件动态添加筛选器,SqlBuilder的条件判断变得异常简洁:
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 });
// 分类筛选(多选)
if (categoryIds?.Any() == true)
builder.Where("CategoryId IN @categoryIds", new { categoryIds });
与传统字符串拼接相比,这种方式避免了繁琐的AND拼接判断,且天然支持参数化查询,有效防止SQL注入。
高级实战:复杂场景解决方案
多模板复用
在分页查询场景中,通常需要同时构建列表查询和总数查询,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);
高级筛选器组合
通过OrWhere方法可实现复杂的OR条件组合,需注意SqlBuilder会将所有OR条件包裹在括号中:
builder.Where("Role = 'Admin'")
.OrWhere("Department = @dept", new { dept = "IT" })
.OrWhere("Title LIKE @title", new { title = "%Manager%" });
生成的WHERE子句为: WHERE Role = 'Admin' AND ( Department = @dept OR Title LIKE @title )
这种处理方式避免了复杂的逻辑运算符优先级问题,确保查询逻辑正确性。
最佳实践与避坑指南
参数管理技巧
- 集中参数添加:通过
AddParameters方法添加全局参数
builder.AddParameters(new { TenantId = currentTenantId })
.Where("TenantId = @TenantId");
- 动态参数名处理:使用
nameof避免硬编码
var keyWord = "test";
builder.Where($"{nameof(Product.Name)} LIKE @{nameof(keyWord)}", new { keyWord });
常见陷阱解析
-
OrWhere逻辑组合:所有OrWhere条件会被合并为
(A OR B OR C),与普通Where条件用AND连接,如Dapper.SqlBuilder/Readme.md中所述 -
模板标记冲突:避免自定义标记与SQL注释冲突,建议使用独特命名如
/**custom_where**/ -
重复添加问题:同一类型子句多次添加会自动合并,无需手动处理分隔符
性能优化与扩展
查询缓存策略
对于频繁执行的动态查询,可结合Dapper的缓存机制优化性能:
var cacheKey = $"Query_{queryParams.GetHashCode()}";
var cachedSql = MemoryCache.Get(cacheKey) as string;
if (cachedSql == null)
{
var template = builder.AddTemplate(baseSql);
cachedSql = template.RawSql;
MemoryCache.Set(cacheKey, cachedSql, TimeSpan.FromMinutes(30));
}
// 使用缓存的SQL执行查询
var result = connection.Query(cachedSql, queryParams);
自定义查询片段
通过继承SqlBuilder扩展自定义查询类型,例如添加FullText搜索子句:
public class AdvancedSqlBuilder : SqlBuilder
{
public AdvancedSqlBuilder FullTextSearch(string column, string keyword)
{
return AddClause("fulltext",
$"CONTAINS({column}, @keyword)",
new { keyword },
" AND ", "AND ");
}
}
项目资源与学习路径
- 官方文档:docs/index.md
- API参考:Dapper.SqlBuilder/PublicAPI.Shipped.txt
- 测试案例:tests/Dapper.Tests/SqlBuilderTests.cs
- 性能基准:benchmarks/Dapper.Tests.Performance/Benchmarks.Dapper.cs
掌握SqlBuilder不仅能提升代码质量,更能显著降低维护成本。下一篇我们将探讨如何结合表达式树构建类型安全的动态查询,敬请关注!
本文示例代码已同步至项目示例库,可通过
git clone https://gitcode.com/gh_mirrors/dapper3/Dapper获取完整项目。
【免费下载链接】Dapper 项目地址: https://gitcode.com/gh_mirrors/dapper3/Dapper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




