C#.NET FluentSqlKata 全面解析:基于链式语法的动态 SQL 构建

简介

在使用 SqlKata 构建 SQL 时,虽然其链式 API 强大灵活,但仍需通过字符串或匿名字段进行表与列的映射,缺乏对实体类型和字段的静态检查。FluentSqlKata 基于 SqlKata,提供了一套基于表达式的强类型查询构建能力,能够:

  • 通过 Lambda 表达式指定实体与列,更安全、可重构

  • 保留 SqlKata 的所有特性与多数据库编译器支持

  • 在运行时动态构造 ORDER BY 时,支持别名排序等高级功能

支持环境与安装

  • 目标框架:.NET Standard 2.0,兼容 .NET Framework 4.6.1+.NET Core 2.0+.NET 5/6/7/8/9/10

  • 安装命令:

shell 复制代码
dotnet add package FluentSqlKata --version 1.1.7

核心功能

强类型查询

使用 FluentQuery.Query() 开始,From(() => alias) 指定实体别名,后续所有列、条件、排序均通过表达式指定:

csharp 复制代码
var query = FluentQuery.Query()
    .From(() => myCust)
    .Select(() => result.CustomerId, () => myCust.Id)
    .Where(q => q.Where(() => myCust.Name, "John"))
    .OrderByColumn(() => myCust.Name);

动态别名排序

对于 SelectRaw 或计算列,支持 OrderByAlias(() => aliasProp),自动以别名生成 ORDER BY

csharp 复制代码
.SelectRaw(() => model.Name, "ISNULL({0}, 'Unknown')", () => myCust.Name)
.OrderByAlias(() => model.Name);

联表与聚合

支持多种 Join 重载,包括表达式构造的 ON 条件;GroupBySelectCount 等聚合 APISqlKata 保持一致:

csharp 复制代码
.Join(() => myCont, () => myCont.CustomerId, () => myCust.Id)
.SelectCount(() => result.Count, () => myCont.Id)
.GroupBy(() => myCust.Name);

API 详解

方法 说明
FluentQuery.Query() 创建一个新的强类型查询构建器
.From(() => alias) 指定根表实体及其别名
.Select(exprAlias, exprColumn) 添加列映射,并指定结果字段
.Where(Func<Query, Query>) 通过内部 SqlKata API 构造过滤条件
.Join(...) 多种重载,可按表达式或列映射方式构造联表
.SelectRaw(alias, fmt, expr...) 原生 SQL 片段映射,同时支持别名排序
.SelectCount(alias, expr) 生成 COUNT(...) AS alias 聚合列
.GroupBy(expr...) 指定分组字段
.OrderByColumn(expr) 按指定列排序
.OrderByAlias(expr) 按先前定义的列别名排序
.Compile(compiler) 使用指定编译器生成最终 SQL 与参数

用法示例

csharp 复制代码
public class Customer
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime LastUpdated { get; set; }
}

基本查询

使用 FluentQuery 构建类型安全的 SELECT 查询:

csharp 复制代码
using FluentSqlKata;
using SqlKata;
using SqlKata.Execution;
using System.Data.SqlClient;

public async Task Main()
{
    using var connection = new SqlConnection("Server=localhost;Database=testdb;Trusted_Connection=True;");
    var compiler = new SqlServerCompiler();
    var db = new QueryFactory(connection, compiler);

    Customer myCust = null;
    (string CustomerId, string CustomerName) result = default;

    var query = FluentQuery.Query()
        .From(() => myCust)
        .Select(() => result.CustomerId, () => myCust.Id)
        .Select(() => result.CustomerName, () => myCust.Name);

    var customers = await db.FromQuery(query).GetAsync<(string, string)>();

    foreach (var customer in customers)
    {
        Console.WriteLine($"ID: {customer.Item1}, Name: {customer.Item2}");
    }
}

条件查询

使用类型安全的 Where 方法:

csharp 复制代码
Customer myCust = null;
(string CustomerId, string CustomerName) result = default;

var query = FluentQuery.Query()
    .From(() => myCust)
    .Select(() => result.CustomerId, () => myCust.Id)
    .Select(() => result.CustomerName, () => myCust.Name)
    .Where(q => q.Where(() => myCust.Name, "John")
                .OrWhereContains(() => myCust.Name, "oh"));

var query_str = new SqlServerCompiler().Compile(query).ToString();
Console.WriteLine(query_str);

连接(JOIN)

类型安全的 JOIN 查询:

csharp 复制代码
Contact myCont = null;
Customer myCust = null;
(string FirstName, string LastName, string CustomerId, string CustomerName) result = default;

var query = FluentQuery.Query()
    .From(() => myCont)
    .Join(() => myCust, () => myCust.Id, () => myCont.CustomerId)
    .Select(() => result.FirstName, () => myCont.FirstName)
    .Select(() => result.LastName, () => myCont.LastName)
    .Select(() => result.CustomerId, () => myCont.CustomerId)
    .Select(() => result.CustomerName, () => myCust.Name);

var query_str = new SqlServerCompiler().Compile(query).ToString();
Console.WriteLine(query_str);

优缺点

优点

  • 类型安全:通过表达式引用表和列,编译器捕获拼写错误。

  • 灵活性:继承 SqlKata 的复杂查询支持(子查询、JOINCTE)。

  • 高性能:结合 Dapper,性能接近原生 ADO.NET

  • 跨数据库支持:通过 SqlKata 的编译器适配多种数据库。

缺点

  • 学习曲线:表达式语法(如 () => myCust.Name)比 SqlKata 的字符串语法复杂。

  • 部分功能依赖字符串:插入、更新和删除仍使用 SqlKata 的字符串-based API

  • 文档有限:FluentSqlKata 的文档较少,需参考 SqlKata 文档和 GitHub 示例。

  • 依赖 SqlKata:增加了依赖项,需熟悉 SqlKata 的核心概念。

示例项目

csharp 复制代码
using Microsoft.AspNetCore.Mvc;
using FluentSqlKata;
using SqlKata;
using SqlKata.Execution;
using System.Threading.Tasks;

public class Customer
{
    public string Id { get; set; }
    public string Name { get; set; }
    public DateTime LastUpdated { get; set; }
}

[ApiController]
[Route("api/customers")]
public class CustomersController : ControllerBase
{
    private readonly QueryFactory _db;

    public CustomersController(QueryFactory db)
    {
        _db = db;
    }

    [HttpGet]
    public async Task<IActionResult> Search([FromQuery] string searchText)
    {
        Customer myCust = null;
        (string CustomerId, string CustomerName) result = default;

        var query = FluentQuery.Query()
            .From(() => myCust)
            .Select(() => result.CustomerId, () => myCust.Id)
            .Select(() => result.CustomerName, () => myCust.Name);

        if (!string.IsNullOrEmpty(searchText))
        {
            query.Where(q => q.WhereContains(() => myCust.Name, searchText));
        }

        var customers = await _db.FromQuery(query).GetAsync<(string, string)>();
        return Ok(customers);
    }
}

启动配置:

csharp 复制代码
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddTransient<QueryFactory>(sp =>
        {
            var connection = new SqlConnection("Server=localhost;Database=testdb;Trusted_Connection=True;");
            var compiler = new SqlServerCompiler();
            return new QueryFactory(connection, compiler);
        });
    }
}
相关推荐
kylezhao20197 小时前
C# 语言基础(变量、数据类型、流程控制、面向对象编程)
开发语言·计算机视觉·c#·visionpro
翩若惊鸿_7 小时前
【无标题】
开发语言·c#
搬砖的工人8 小时前
写了一个IIS监控工具,对付“假死“后自动重启站点
c#
红黑色的圣西罗11 小时前
对象池简述
unity·c#
水龙吟啸12 小时前
基于Orbbec-Gemini深度相机与SFM-2D to 3D重建算法、手部识别视觉算法、Unity运动控制的3D水果切割游戏
python·深度学习·神经网络·c#·游戏引擎·3d视觉·3d重建
小码编匠15 小时前
工业视觉 C# + OpenCvSharp 的模板匹配实战
后端·c#·.net
步步为营DotNet15 小时前
深入理解.NET 中的IHostedService:后台任务管理的基石
java·网络·.net
月巴月巴白勺合鸟月半16 小时前
几种 HTML 转 PDF的方式
pdf·c#
bugcome_com17 小时前
简述 C# 成员修饰符(Modifier)——从整体到细节全面解析
c#
helloworddm18 小时前
防止应用多开-WPF
服务器·架构·c#