Dapper.SqlBuilder使用指南:动态构建SQL查询从未如此简单
【免费下载链接】Dapper 项目地址: https://gitcode.com/gh_mirrors/dapper3/Dapper
你是否还在为拼接SQL字符串而烦恼?是否经常因为条件判断导致SQL语句臃肿不堪?Dapper.SqlBuilder正是为解决这些问题而生,它让动态SQL构建变得优雅而高效。本文将带你快速掌握Dapper.SqlBuilder的使用方法,读完你将能够:
- 理解动态SQL构建的核心痛点
- 掌握SqlBuilder的基本用法和高级技巧
- 实现条件查询、分页等常见场景
- 避免SQL注入风险
什么是Dapper.SqlBuilder
Dapper.SqlBuilder是Dapper库的一个重要组件,专门用于动态构建SQL查询语句。它通过模板和条件拼接的方式,让开发者能够轻松应对复杂的查询需求,同时保持代码的可读性和可维护性。
核心功能代码实现位于Dapper.SqlBuilder/SqlBuilder.cs,主要提供了一系列用于构建SQL片段的方法,如Where、Select、OrderBy等。
快速开始
安装Dapper.SqlBuilder
要使用Dapper.SqlBuilder,你需要先安装相应的NuGet包。在项目中通过NuGet引用Dapper.SqlBuilder即可开始使用。
基本用法示例
下面是一个简单的示例,展示如何使用SqlBuilder构建查询:
var builder = new SqlBuilder()
.Where("a = @a", new { a = 1 })
.Where("b = @b", new { b = 2 })
.OrderBy("a")
.OrderBy("b");
var selector = builder.AddTemplate("select * from table /**where**/ /**orderby**/");
var rows = connection.Query(selector.RawSql, selector.Parameters);
这段代码会生成如下SQL:
select * from table WHERE a = @a AND b = @b ORDER BY a , b
核心功能详解
SQL模板系统
SqlBuilder的核心是模板系统,通过AddTemplate方法创建模板,使用/**关键词**/作为占位符,后续调用相应方法时会自动替换这些占位符。
支持的主要占位符包括:
/**where**/- 对应Where和OrWhere方法/**select**/- 对应Select方法/**orderby**/- 对应OrderBy方法/**groupby**/- 对应GroupBy方法/**having**/- 对应Having方法/**set**/- 对应Set方法(用于UPDATE语句)
条件查询构建
最常用的功能是动态构建WHERE子句,SqlBuilder提供了Where和OrWhere两种方法:
var builder = new SqlBuilder();
var template = builder.AddTemplate("select * from Users /**where**/");
if (!string.IsNullOrEmpty(username))
builder.Where("Username = @username", new { username });
if (roleId.HasValue)
builder.Where("RoleId = @roleId", new { roleId });
if (statuses != null && statuses.Any())
builder.Where("Status IN @statuses", new { statuses });
注意:OrWhere的使用需要特别注意,根据Dapper.SqlBuilder/Readme.md中的说明,OrWhere目前存在逻辑上的限制,可能不会按预期生成OR条件。
动态排序和分页
结合OrderBy方法和ROW_NUMBER()函数,可以轻松实现动态排序和分页功能:
var builder = new SqlBuilder();
var selectTemplate = builder.AddTemplate(@"select X.* from (
select us.*, ROW_NUMBER() OVER (/**orderby**/) AS RowNumber
from Users us
/**where**/
) as X
where RowNumber between @start and @finish", new { start, finish });
builder.OrderBy("CreateTime desc");
builder.OrderBy("UserId");
if (searchText != null)
builder.Where("UserName like @searchText", new { searchText = $"%{searchText}%" });
var users = connection.Query<User>(selectTemplate.RawSql, selectTemplate.Parameters);
高级技巧
参数安全处理
SqlBuilder自动处理参数化查询,避免SQL注入风险。所有通过方法传递的参数都会被自动添加到查询参数中:
// 安全的参数化查询
builder.Where("UserName = @name", new { name = inputName });
// 生成的SQL会使用参数化查询,而非直接拼接字符串
// WHERE UserName = @name
复用SQL片段
对于复杂查询,可以将重复使用的SQL片段提取出来,提高代码复用性:
// 定义可复用的查询条件
public SqlBuilder AddCommonFilters(SqlBuilder builder, FilterModel filters)
{
if (filters.MinDate.HasValue)
builder.Where("CreateTime >= @minDate", new { filters.MinDate });
if (filters.MaxDate.HasValue)
builder.Where("CreateTime <= @maxDate", new { filters.MaxDate });
return builder;
}
// 使用复用的查询条件
var builder = new SqlBuilder();
AddCommonFilters(builder, filters);
// 添加其他条件...
多模板共享条件
一个SqlBuilder实例可以创建多个模板,共享相同的查询条件,这在同时需要查询数据和总记录数时非常有用:
var builder = new SqlBuilder()
.Where("Status = 1");
var countTemplate = builder.AddTemplate("select count(*) from Products /**where**/");
var listTemplate = builder.AddTemplate("select * from Products /**where**/ /**orderby**/");
builder.OrderBy("Price desc");
var total = connection.ExecuteScalar<int>(countTemplate.RawSql, countTemplate.Parameters);
var products = connection.Query<Product>(listTemplate.RawSql, listTemplate.Parameters);
实际应用案例
动态搜索功能
实现一个支持多条件组合的搜索功能:
public List<Product> SearchProducts(SearchCriteria criteria)
{
using (var connection = new SqlConnection(connectionString))
{
var builder = new SqlBuilder();
var template = builder.AddTemplate("select * from Products /**where**/ /**orderby**/");
// 关键词搜索
if (!string.IsNullOrEmpty(criteria.Keyword))
{
builder.Where("(Name like @keyword or Description like @keyword)",
new { keyword = $"%{criteria.Keyword}%" });
}
// 价格范围过滤
if (criteria.MinPrice.HasValue)
builder.Where("Price >= @minPrice", new { criteria.MinPrice });
if (criteria.MaxPrice.HasValue)
builder.Where("Price <= @maxPrice", new { criteria.MaxPrice });
// 分类过滤
if (criteria.CategoryIds != null && criteria.CategoryIds.Any())
builder.Where("CategoryId IN @categoryIds", new { criteria.CategoryIds });
// 排序
builder.OrderBy(criteria.SortBy + (criteria.IsDescending ? " desc" : ""));
return connection.Query<Product>(template.RawSql, template.Parameters).ToList();
}
}
动态更新语句
SqlBuilder不仅可以构建查询语句,还可以用于构建UPDATE语句:
public void UpdateProduct(Product product, List<string> fieldsToUpdate)
{
using (var connection = new SqlConnection(connectionString))
{
var builder = new SqlBuilder();
var template = builder.AddTemplate("update Products /**set**/ where ProductId = @productId",
new { product.Id });
if (fieldsToUpdate.Contains("Name"))
builder.Set("Name = @name", new { product.Name });
if (fieldsToUpdate.Contains("Price"))
builder.Set("Price = @price", new { product.Price });
if (fieldsToUpdate.Contains("Stock"))
builder.Set("Stock = @stock", new { product.Stock });
connection.Execute(template.RawSql, template.Parameters);
}
}
注意事项和限制
OrWhere的使用限制
根据官方文档,OrWhere目前存在逻辑组合问题。当同时使用Where和OrWhere时,生成的SQL可能不符合预期:
sql.Where("a = @a1");
sql.OrWhere("b = @b1");
sql.Where("a = @a2");
sql.OrWhere("b = @b2");
上面的代码会生成:
a = @a1 AND b = @b1 AND a = @a2 AND b = @b2
而不是预期的:
a = @a1 OR b = @b1 AND a = @a2 OR b = @b2
参数命名冲突
当多次添加参数时,如果参数名相同,后面的参数值会覆盖前面的。因此建议使用唯一的参数名,或在不同条件中使用不同的参数名。
总结
Dapper.SqlBuilder为动态SQL构建提供了简洁而强大的解决方案,通过模板系统和链式API,让原本复杂的动态SQL拼接变得优雅而直观。无论是简单的条件查询还是复杂的多表连接,SqlBuilder都能显著提高代码的可读性和可维护性。
官方文档和更多示例可以参考Dapper.SqlBuilder/Readme.md,更多Dapper相关功能请查阅项目README.md。
掌握SqlBuilder将使你在处理动态查询时事半功倍,让SQL构建不再是开发中的痛点!
【免费下载链接】Dapper 项目地址: https://gitcode.com/gh_mirrors/dapper3/Dapper
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考




