Dappe&&Dapper.SqlBuilde&&SimpleBuilder.Creat和SimpleBuilder.CreateFluent比较对比差异

Dapper介绍

Dapper是一个用于.NET的开源、轻量级对象关系映射(ORM)库。Dapper简化了SQL查询的构建和执行,提供了一组丰富的工具,用于与数据库无缝集成。

在本文中,我们将深入探讨使用Dapper与SQLite数据库交互的实际示例,并突出其优势。此外,我们还将介绍一个有价值的配套库Dapper.SimpleSqlBuilder,旨在通过简化构造动态SQL查询的过程来增强Dapper体验。

Dapper入门

让我们先来研究一个常见的场景。假设您在SQLite数据库中有一个名为Users的表,并且您想要检索具UserTypeId为4和Role为Admin的用户。以下Dapper代码可实现此目的:

using Dapper;
using Microsoft.Data.Sqlite;
 
var userTypeId = 4;
var role = "Admin";
 
var sql = @"
SELECT * FROM Users
WHERE UserTypeId = @userTypeId
AND Role = @role";
 
using var connection = new SqliteConnection("Data Source=database.db");
var users = connection.Query<User>(sql, new { userTypeId, role });

这段简明扼要的代码演示了Dapper在执行SQL查询和从数据库中检索数据方面的强大功能和简单性。

Dapper.SimpleSqlBuilder简介

什么是Dapper.SimpleSqlBuilder?
Dapper.SimpleSqlBuilder是一个库,它通过提供一种简单、高效和流畅的方式来生成静态和动态SQL查询,从而增强了Dapper体验。利用字符串插值和流畅的API,该库允许开发人员轻松构建安全且参数化的SQL查询。

这不是一个新奇的想法,因为已经有关于此的文章,并且还有其他库在做类似的事情。尽管如此,我还是想构建一些简单、易于使用、内存高效、快速、安全并创建参数化SQL查询的东西。

主要特点
提供一种使用字符串插值编写SQL查询的简单自然方法
用于构建SQL查询的可链接方法和流畅的API
支持在查询中重用参数
依赖注入支持
用于生成动态SQL查询的条件方法
高性能和内存效率高。与Dapper的SqlBuilder相比,性能相似或更好
该库提供了两个用于构建SQL查询的生成器:

构建器——用于构建静态、动态和复杂的SQL查询
Fluent Builder——用于使用Fluent API构建动态SQL查询
构建器
让我们重新审视前面的场景,但这次使用Dapper.SimpleSqlBuilder Builder的。

using Dapper;
using Dapper.SimpleSqlBuilder;
using Microsoft.Data.Sqlite;
 
var userTypeId = 4;
var role = "Admin";
 
var builder = SimpleBuilder.Create($@"
SELECT * FROM Users
WHERE UserTypeId = {userTypeId}
AND Role = {role}");
 
using var connection = new SqliteConnection("Data Source=database.db");
var users = connection.Query<User>(builder.Sql, builder.Parameters);

我知道你们中的一些人已经在想,这不安全,你正在使用字符串插值,这可能会导致SQL注入。

您的担忧是有道理的;但是,该库通过捕获传递到插值字符串中的值并创建参数化的SQL语句来缓解这种情况,如下所示。

传递到插值字符串中的所有值都将放入Dapper的DynamicParameters集合中。

SELECT * FROM Users
WHERE UserTypeId = @p0
AND Role = @p1

使用相同的方案,让我们使查询动态化。

using Dapper;
using Dapper.SimpleSqlBuilder;
using Microsoft.Data.Sqlite;
 
var users = GetUsers(null, "Admin");
 
IEnumerable<User> GetUsers(int? userTypeId = null, string role = null)
{
 
    var builder = SimpleBuilder.Create($"SELECT * FROM Users")
      .AppendNewLine(userTypeId.HasValue || 
                     !string.IsNullOrWhiteSpace(role), $"WHERE 1 = 1")
      .Append(userTypeId.HasValue, $"AND UserTypeId = {userTypeId}")
      .Append(!string.IsNullOrWhiteSpace(role), $"AND Role = {role}");
 
    using var connection = new SqliteConnection("Data Source=database.db");
    return users = connection.Query<User>(builder.Sql, builder.Parameters);
}

生成的SQL将是:

SELECT * FROM Users
WHERE 1 = 1 AND Role = @p0

您可以在文档中查看Builder的完整功能集。

让我们快速谈谈SQL注入
我们都知道SQL注入的危险,但是,如果你不知道,我建议你在这里阅读它。

那么库是如何防止这种情况的呢?
该库通过强制您使用字符串插值编写所有SQL查询来缓解这种情况,这是为了确保捕获传递到插值字符串中的值并对其进行参数化。由于此限制,以下代码将无法编译。

// Scenario 1: Won't compile
var builder = SimpleBuilder.Create("SELECT * FROM User");
 
// Scenario 2: Won't compile
var sql = "SELECT * FROM User";
builder = SimpleBuilder.Create(sql);
 
// Scenario 3: Won't compile
builder = SimpleBuilder.Create(sql + " WHERE ROLE IS NOT NULL");
 
// Scenario 4: Won't compile
sql = $"SELECT * FROM User WHERE UserTypeId = {userTypeId}";
builder = SimpleBuilder.Create(sql);
 
// Scenario 5: Won't compile
builder = SimpleBuilder.Create(sql + $" AND Role = {role}");

流畅的构建器
Fluent Builder 提供了一种更具表现力的方式来构建具有Fluent API的动态 SQL 查询,并支持SELECT、INSERT、UPDATE和DELETE操作。

我们只会看Select操作,以保持本文的简短和甜蜜。但是,您可以在文档中了解有关Fluent Builder的其他操作和功能的更多信息。

选择“构建器”
使用前面提到的相同方案,我们将使用Fluent Builder来构建SQL查询。

var userTypeId = 4;
var role = "Admin";
 
var builder = SimpleBuilder.CreateFluent()
    .Select($"*")
    .From($"Users")
    .Where($"UserTypeId = {userTypeId}")
    .Where($"Role = {role}");
 
using var connection = new SqliteConnection("Data Source=database.db");
var users = connection.Query<User>(builder.Sql, builder.Parameters);

生成的SQL将是:

SELECT *
FROM Users
WHERE UserTypeId = @p0 AND Role = @p1

让我们看另一个例子,但这次我们将使SQL查询动态化。

var filter = new Filter { UserTypeId = null, 
             Roles = new [] { "Admin", "User" }, IncludeUsersWithoutRole = true };
var users = GetUsers(filter);
 
IEnumerable<User> GetUsers(Filter? filter = null)
{
    var builder = SimpleBuilder.CreateFluent()
        .Select($"*")
        .From($"User")
        .Where(filter?.UserTypeId.HasValue == true, $"UserTypeId = {filter.UserTypeId}")
        .OrWhere(filter?.Roles?.Length > 0, $"Role IN {filter.Roles}")
        .OrWhere(filter?.IncludeUsersWithoutRole == true, $"Role IS NULL");
 
    using var connection = new SqliteConnection("Data Source=database.db");
    return connection.Query<User>(builder.Sql, builder.Parameters);
}

生成的SQL将是:

SELECT *
FROM Users
WHERE Role IN @p0 OR Role IS NULL

Select Builder 还支持:

Distinct、Joins、OrderBy、Having和GroupBy子句
分页:Limit、Offset和Fetch子句
Where筛选器(复杂筛选器语句)
它与Dapper相比如何?
下面的代码显示了该库与Dapper和Dapper的SqlBuilder的比较情况。

using var connection = new SqliteConnection("Data Source=database.db");
 
// Building and executing SQL query with Dapper
 
var sql = @"
SELECT * FROM Users
WHERE UserTypeId = @userTypeId 
AND Role = @role";
 
var users = connection.Query<User>(sql, new { userTypeId, role })
 
// Building and executing SQL query with Dapper's SqlBuilder
 
var sqlBuilder = new SqlBuilder()
    .Where("UserTypeId = @userTypeId", new { userTypeId })
    .Where("Role = @role", new { role });
 
var template = sqlBuilder.AddTemplate("SELECT * FROM Users /**where**/");
users = connection.Query<User>(template.RawSql, template.Parameters);
 
// Building and executing SQL query with the Builder (Dapper.SimpleSqlBuilder)
 
var builder = SimpleBuilder.Create($@"
SELECT * FROM Users
WHERE UserTypeId = {userTypeId}
AND Role = {role}");
 
users = connection.Query<User>(builder.Sql, builder.Parameters);
 
// Building and executing SQL query with the Fluent Builder (Dapper.SimpleSqlBuilder)
 
var fluentBuilder = SimpleBuilder.CreateFluent()
    .Select($"*")
    .From($"Users")
    .Where($"UserTypeId = {userTypeId}")
    .Where($"Role = {role}");
 
users = connection.Query<User>(fluentBuilder.Sql, fluentBuilder.Parameters);

正如你所看到的,该库减轻了使用Dapper时所需的一些仪式,并提供了一种简单自然的编写SQL查询的方法。

性能
性能始终是相对的,取决于方案和其他因素(例如,硬件、操作系统等),但是,下面的结果很好地指示了库的性能。

该基准测试显示了Builder和Fluent Builder与Dapper的SqlBuilder相比仅用于构建查询的性能(这不对SQL执行进行基准测试)。

在这里插入图片描述

基准测试结果在撰写本文时有效。要查看最新的基准测试结果,请参阅基准测试页面了解更多详细信息。

结论
我希望您喜欢阅读这篇文章并学到一些新东西。Dapper.SimpleSqlBuilder是一个很酷的库(我希望它是😄),可以满足特定的需求,我希望你觉得它有用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值