Dapper.SqlBuilder使用指南:动态构建SQL查询从未如此简单

Dapper.SqlBuilder使用指南:动态构建SQL查询从未如此简单

【免费下载链接】Dapper 【免费下载链接】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 Logo

核心功能代码实现位于Dapper.SqlBuilder/SqlBuilder.cs,主要提供了一系列用于构建SQL片段的方法,如WhereSelectOrderBy等。

快速开始

安装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提供了WhereOrWhere两种方法:

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 【免费下载链接】Dapper 项目地址: https://gitcode.com/gh_mirrors/dapper3/Dapper

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值