KnightMoves.SqlObjects 是一个 .NET NuGet 包库,用于实现基于对象的 SQL 生成器。与其他依赖字符串操作(如串联和插值)的 SQL 构建器不同,此库采用包装 SQL 语法为 C# 对象的方法,从而让整个 SQL 查询由对象组成。这种方式带来了如下优势:
首先,在 Visual Studio 中创建一个简单的 Console 应用程序,并通过 NuGet 安装 KnightMoves.SqlObjects 包。步骤如下:
安装完成后,在代码中加入如下 using 声明即可开始使用:
C#using KnightMoves.SqlObjects;

构造一个基本的 SELECT * FROM Products 查询非常简单。下面这个例子展示了如何通过静态类 TSQL 来生成 SQL 查询。
C#using KnightMoves.SqlObjects;
namespace AppKnightMoves
{
internal class Program
{
static void Main(string[] args)
{
var query = TSQL.SELECT()
.FROM("Products").Build();
// 输出生成的 SQL 字符串
Console.WriteLine(query);
}
}
}

这段代码展示了如何快速构造一个没有列过滤的 SQL 查询。
在实际的开发中,我们经常需要指定查询中的具体列,并为部分列设置别名。KnightMoves.SqlObjects 提供了 COLUMN() 方法和链式调用 .AS() 来实现这一功能。
C#using KnightMoves.SqlObjects;
namespace AppKnightMoves
{
internal class Program
{
static void Main(string[] args)
{
// 利用 COLUMN() 方法指定每个查询列,
var query = TSQL.SELECT()
.COLUMN("ProductID").AS("Id")
.COLUMN("ProductName")
.COLUMN("Price")
.FROM("Products").Build();
Console.WriteLine(query);
}
}
}

此外,有些情况下可以直接在 COLUMN() 方法中传递第三个参数作为别名(取决于具体实现),这为代码的简洁性提供了另一种选择。
如果需要在查询中指定多个列,重复调用 COLUMN() 方法显得比较繁琐。借助复数形式的 COLUMNS() 方法,你可以一次性传入一个列名集合,甚至添加表的前缀来帮助区分不同表中的列。
下面的代码展示了如何用一个字符串数组一次性构造查询列:
C#using KnightMoves.SqlObjects;
using KnightMoves.SqlObjects.SqlCode.TSQL;
namespace AppKnightMoves
{
internal class Program
{
static void Main(string[] args)
{
var columns = new List<TSQLColumn>
{
new TSQLColumn { MultiPartIdentifier = "p", ColumnName = "ProductID" },
new TSQLColumn { MultiPartIdentifier = "p", ColumnName = "ProductName", Alias = "Name" }
};
var sql = TSQL
.SELECT()
.COLUMNS(columns)
.FROM("dbo", "Products", "p")
.Build();
Console.WriteLine(sql);
}
}
}

这种方式在写联接查询时尤其有用,可以避免列名称的混淆,提高代码可读性。
很多业务场景需要从多个表中联合查询数据。以下示例展示了如何通过库中的 INNERJOIN() 方法构造一个内联接查询,同时使用 ON() 和 IsEqualTo() 方法来指定联接条件。
假设我们的目标 SQL 如下:
SQLSELECT [p].[ProductID], [p].[ProductName], [c].[CategoryName]
FROM [Products] AS [p]
INNER JOIN [Categories] AS [c] ON [p].[CategoryID] = [c].[CategoryID]
对应的 C# 示例代码如下:
C#using KnightMoves.SqlObjects;
using KnightMoves.SqlObjects.SqlCode.TSQL;
namespace AppKnightMoves
{
internal class Program
{
static void Main(string[] args)
{
// 构造 SELECT 子句,分别指定来自两个表的查询列(使用别名区分)
var query = TSQL.SELECT()
.COLUMN("ProductID", "p") // 来自 Products 表,别名为 p
.COLUMN("ProductName", "p") // 来自 p 表
.COLUMN("CategoryName", "c") // 来自 Categories 表,别名为 c
.FROM("Products", "p") // 主表及其别名
// 使用 INNERJOIN() 加入 Categories 表,并指定别名 c
.INNERJOIN("Categories", "c")
// 使用 ON() 方法构造联接条件
.ON(
"c", "CategoryID"
).IsEqualTo("p", "CategoryID").Build();
Console.WriteLine(query);
}
}
}

在这个例子中,我们看到:
.IsEqualTo() 来构造,尽管语法上略有区别,但整体思路与 SQL 相近。C#using KnightMoves.SqlObjects;
using KnightMoves.SqlObjects.SqlCode.TSQL;
namespace AppKnightMoves
{
internal class Program
{
static void Main(string[] args)
{
// 构造 INSERT 子句,向 Products 表插入一条新记录
var query = TSQL.INSERT().INTO("Products")
.COLUMN("ProductName").VALUE("苹果")
.COLUMN("CategoryID").VALUE(1)
.COLUMN("UnitPrice").VALUE(5.50M)
.Build();
Console.WriteLine(query);
}
}
}

KnightMoves.SqlObjects 通过对象化的构建方式,实现了几乎完全匹配 T-SQL 语法的查询生成。尽管某些细节(例如使用 COLUMN() 方法和 IsEqualTo() 操作符)与直接编写 SQL 略有出入,但这正是为了让开发者能够直接以 SQL 思维来编写代码,同时获得编译时类型安全和更好的 IDE 支持。
希望本文能够帮助你快速上手 KnightMoves.SqlObjects,并在实际开发中获得更高的生产力与代码质量。欢迎继续探索、尝试并分享你的使用经验!
本文作者:技术老小子
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!