SQLSugar 快速入门:从基础到实战查询与使用指南

目录

​编辑

[一、SQLSugar 简介](#一、SQLSugar 简介)

[二、SQLSugar 环境搭建](#二、SQLSugar 环境搭建)

[2.1 安装 SQLSugar](#2.1 安装 SQLSugar)

[2.1.1 通过 Visual Studio NuGet 图形化界面安装](#2.1.1 通过 Visual Studio NuGet 图形化界面安装)

[2.1.2 通过 NuGet 命令行安装](#2.1.2 通过 NuGet 命令行安装)

[2.2 引用 SQLSugar 命名空间](#2.2 引用 SQLSugar 命名空间)

[三、SQLSugar 核心初始化配置](#三、SQLSugar 核心初始化配置)

[3.1 基础初始化(非 IOC 模式)](#3.1 基础初始化(非 IOC 模式))

[3.1.1 单数据库配置](#3.1.1 单数据库配置)

[3.1.2 多数据库配置](#3.1.2 多数据库配置)

[3.2 IOC 模式初始化(适用于ASP.NET Core)](#3.2 IOC 模式初始化(适用于ASP.NET Core))

[3.2.1 配置服务(Program.cs/.NET 6+)](#3.2.1 配置服务(Program.cs/.NET 6+))

[3.2.2 在控制器中注入使用](#3.2.2 在控制器中注入使用)

[3.3 连接字符串配置(AppSettings.json)](#3.3 连接字符串配置(AppSettings.json))

[四、实体类映射(ORM 核心)](#四、实体类映射(ORM 核心))

[4.1 特性映射(推荐)](#4.1 特性映射(推荐))

[4.1.1 常用特性说明](#4.1.1 常用特性说明)

[4.1.2 实体类示例](#4.1.2 实体类示例)

[4.2 约定映射(默认)](#4.2 约定映射(默认))

[4.3 导航属性配置](#4.3 导航属性配置)

[五、SQLSugar 常见查询举例与对应 SQL 实现](#五、SQLSugar 常见查询举例与对应 SQL 实现)

[5.1 单表查询](#5.1 单表查询)

[5.1.1 查询所有数据(无条件)](#5.1.1 查询所有数据(无条件))

[5.1.2 根据主键查询单条数据](#5.1.2 根据主键查询单条数据)

[5.1.3 条件查询(单条件 / 多条件)](#5.1.3 条件查询(单条件 / 多条件))

[5.1.4 模糊查询(Like)](#5.1.4 模糊查询(Like))

[5.1.5 范围查询(In/Between)](#5.1.5 范围查询(In/Between))

[5.1.6 排序查询(OrderBy)](#5.1.6 排序查询(OrderBy))

[5.1.7 限制结果集(Take/Skip)](#5.1.7 限制结果集(Take/Skip))

[5.1.8 分页查询](#5.1.8 分页查询)

[5.1.9 统计查询(Count/Sum/Avg/Max/Min)](#5.1.9 统计查询(Count/Sum/Avg/Max/Min))

[5.1.10 分组统计查询(GroupBy)](#5.1.10 分组统计查询(GroupBy))

[5.2 多表联查](#5.2 多表联查)

[5.2.1 两表联查(左联:Left Join)](#5.2.1 两表联查(左联:Left Join))

[5.2.2 两表联查(内联:Inner Join)](#5.2.2 两表联查(内联:Inner Join))

[5.2.3 三表联查(左联 + 内联)](#5.2.3 三表联查(左联 + 内联))

[5.3 子查询](#5.3 子查询)

[5.3.1 子查询作为条件(Exists/In)](#5.3.1 子查询作为条件(Exists/In))

[5.3.2 子查询作为结果集(From 子查询)](#5.3.2 子查询作为结果集(From 子查询))

[5.4 自定义 SQL 查询](#5.4 自定义 SQL 查询)

[5.4.1 执行查询 SQL(返回实体类 / 匿名对象)](#5.4.1 执行查询 SQL(返回实体类 / 匿名对象))

[5.4.2 带参数的自定义 SQL(防止 SQL 注入)](#5.4.2 带参数的自定义 SQL(防止 SQL 注入))

[六、SQLSugar 详细使用指导](#六、SQLSugar 详细使用指导)

[6.1 CRUD 操作完整示例(除查询外)](#6.1 CRUD 操作完整示例(除查询外))

[6.1.1 新增操作(Insert)](#6.1.1 新增操作(Insert))

[6.1.2 修改操作(Update)](#6.1.2 修改操作(Update))

[6.1.3 删除操作(Delete)](#6.1.3 删除操作(Delete))

[6.2 事务处理](#6.2 事务处理)

[6.2.1 手动事务(推荐,灵活控制)](#6.2.1 手动事务(推荐,灵活控制))

[6.2.2 自动事务(简化代码,通过特性或方法)](#6.2.2 自动事务(简化代码,通过特性或方法))

[6.3 缓存功能](#6.3 缓存功能)

[6.3.1 基础缓存使用(内存缓存)](#6.3.1 基础缓存使用(内存缓存))

[6.3.2 自定义 Redis 缓存](#6.3.2 自定义 Redis 缓存)

[6.4 代码生成器](#6.4 代码生成器)

[6.4.1 基础代码生成(生成实体类)](#6.4.1 基础代码生成(生成实体类))

[6.4.2 高级代码生成(生成仓储类 + 服务类)](#6.4.2 高级代码生成(生成仓储类 + 服务类))

[七、SQLSugar 使用注意事项](#七、SQLSugar 使用注意事项)

[7.1 连接与性能相关](#7.1 连接与性能相关)

[7.2 实体类映射相关](#7.2 实体类映射相关)

[7.3 查询相关](#7.3 查询相关)


一、SQLSugar 简介

SQLSugar 是一款轻量级、高性能的 ORM(对象关系映射)框架,基于.NET 平台开发,支持多种数据库(如 SQL Server、MySQL、Oracle、SQLite、PostgreSQL 等)。它兼具了 EF(Entity Framework)的易用性和 Dapper 的高性能,提供了丰富的 API 接口,能轻松实现数据库的增删改查(CRUD)操作,同时支持复杂查询、事务处理、代码优先(Code First)、数据库优先(DB First)等功能,是.NET 开发者在项目开发中操作数据库的优质选择。

相比其他 ORM 框架,SQLSugar 具有以下优势:

  1. 性能优异:采用了高效的 SQL 生成机制和参数化查询,避免 SQL 注入问题,同时减少数据库交互次数,提升查询效率。
  1. 易用性强:API 设计简洁直观,学习成本低,开发者无需编写复杂的 SQL 语句,通过面向对象的方式即可操作数据库。
  1. 功能全面:支持单表查询、多表联查、子查询、分组统计、分页查询等各类查询场景,同时提供事务、缓存、日志、代码生成等辅助功能。
  1. 多数据库支持:只需修改连接字符串和数据库类型配置,即可在不同数据库之间无缝切换,降低项目的数据库迁移成本。
  1. 扩展性好:支持自定义 SQL、存储过程调用、函数调用等,满足复杂业务场景的需求。

二、SQLSugar 环境搭建

2.1 安装 SQLSugar

SQLSugar 可通过 NuGet 包管理器快速安装,支持.NET Framework 4.5+、.NET Core 2.0+、.NET 5/6/7/8 等版本。以下是两种常见的安装方式:

2.1.1 通过 Visual Studio NuGet 图形化界面安装
  1. 打开 Visual Studio,创建或打开一个.NET 项目(如控制台应用、ASP.NET Core Web 应用等)。
  1. 在 "解决方案资源管理器" 中,右键点击项目名称,选择 "管理 NuGet 程序包"。
  1. 在弹出的 NuGet 包管理器界面中,切换到 "浏览" 选项卡,在搜索框中输入 "SQLSugar"。
  1. 找到 "SQLSugarCore"(.NET Core/.NET 5 + 版本)或 "SQLSugar"(.NET Framework 版本),点击 "安装" 按钮,等待安装完成。
2.1.2 通过 NuGet 命令行安装

打开 Visual Studio 的 "程序包管理器控制台"(工具 -> NuGet 包管理器 -> 程序包管理器控制台),根据项目框架版本执行以下命令:

  • .NET Core/.NET 5+:
复制代码

Install-Package SQLSugarCore

  • .NET Framework:
复制代码

Install-Package SQLSugar

2.2 引用 SQLSugar 命名空间

安装完成后,在需要使用 SQLSugar 的代码文件中,引用以下命名空间:

复制代码

using SqlSugar;

using SqlSugar.IOC; // 若使用IOC容器集成,需引用此命名空间

三、SQLSugar 核心初始化配置

在使用 SQLSugar 操作数据库前,需要先进行初始化配置,主要包括创建SqlSugarClient实例、设置连接字符串、配置数据库类型等。SqlSugarClient是 SQLSugar 的核心对象,所有数据库操作都通过该对象完成。

3.1 基础初始化(非 IOC 模式)

适用于小型项目或不需要依赖注入的场景,直接创建SqlSugarClient实例并配置相关参数。

3.1.1 单数据库配置

以 SQL Server 为例,基础初始化代码如下:

复制代码

// 1. 创建连接配置对象

var connectionConfig = new ConnectionConfig

{

ConnectionString = "Server=localhost;Database=TestDB;Uid=sa;Pwd=123456;", // 数据库连接字符串

DbType = DbType.SqlServer, // 数据库类型(SqlServer、MySql、Oracle、Sqlite、PostgreSQL等)

IsAutoCloseConnection = true, // 是否自动关闭数据库连接(建议设置为true,避免连接泄露)

InitKeyType = InitKeyType.Attribute // 主键初始化方式(Attribute:通过实体类特性指定主键;Auto:自动识别主键)

};

// 2. 创建SqlSugarClient实例

SqlSugarClient db = new SqlSugarClient(connectionConfig);

// 3. (可选)配置日志输出(便于调试,查看生成的SQL语句)

db.Aop.OnLogExecuting = (sql, pars) =>

{

Console.WriteLine($"SQL语句:{sql}");

Console.WriteLine($"参数:{string.Join(",", pars.Select(p => $"{p.ParameterName}={p.Value}"))}");

};

3.1.2 多数据库配置

若项目中需要操作多个不同类型的数据库(如同时操作 SQL Server 和 MySQL),可通过ConnectionConfig的ConfigId属性区分不同数据库配置:

复制代码

// 配置SQL Server数据库(ConfigId=1)

var sqlServerConfig = new ConnectionConfig

{

ConfigId = 1,

ConnectionString = "Server=localhost;Database=TestDB_SQLServer;Uid=sa;Pwd=123456;",

DbType = DbType.SqlServer,

IsAutoCloseConnection = true,

InitKeyType = InitKeyType.Attribute

};

// 配置MySQL数据库(ConfigId=2)

var mySqlConfig = new ConnectionConfig

{

ConfigId = 2,

ConnectionString = "Server=localhost;Database=TestDB_MySQL;Uid=root;Pwd=123456;Port=3306;",

DbType = DbType.MySql,

IsAutoCloseConnection = true,

InitKeyType = InitKeyType.Attribute

};

// 创建SqlSugarClient实例,传入多个连接配置

SqlSugarClient db = new SqlSugarClient(new List<ConnectionConfig> { sqlServerConfig, mySqlConfig });

// 使用不同数据库:通过ConfigId获取对应数据库的操作对象

var sqlServerDb = db.GetConnection(1); // SQL Server数据库操作对象

var mySqlDb = db.GetConnection(2); // MySQL数据库操作对象

3.2 IOC 模式初始化(适用于ASP.NET Core)

ASP.NET Core 项目中,推荐使用 IOC(依赖注入)模式集成 SQLSugar,便于项目的解耦和维护。

3.2.1 配置服务(Program.cs/.NET 6+)
复制代码

var builder = WebApplication.CreateBuilder(args);

// 1. 添加SQLSugar服务

builder.Services.AddSqlSugar(new IocConfig

{

ConnectionConfigs = new List<ConnectionConfig>

{

new ConnectionConfig

{

ConfigId = "MainDB", // 配置ID(自定义,用于区分不同数据库)

ConnectionString = builder.Configuration.GetConnectionString("MainDB"), // 从配置文件读取连接字符串

DbType = DbType.SqlServer,

IsAutoCloseConnection = true,

InitKeyType = InitKeyType.Attribute

}

},

Scope = ServiceLifetime.Scoped // 服务生命周期(Scoped:每个请求创建一个实例;Singleton:单例;Transient:每次获取创建一个实例)

});

// 2. 添加其他服务(如MVC控制器)

builder.Services.AddControllersWithViews();

var app = builder.Build();

// 后续中间件配置...

3.2.2 在控制器中注入使用
复制代码

public class UserController : Controller

{

private readonly ISqlSugarClient _db; // 注入ISqlSugarClient接口

// 构造函数注入

public UserController(ISqlSugarClient db)

{

_db = db;

}

// 示例:查询用户列表

public IActionResult UserList()

{

var userList = _db.Queryable<User>().ToList();

return View(userList);

}

}

3.3 连接字符串配置(AppSettings.json)

为了便于项目配置管理,通常将连接字符串配置在AppSettings.json文件中(以ASP.NET Core 为例):

复制代码

{

"Logging": {

"LogLevel": {

"Default": "Information",

"Microsoft.AspNetCore": "Warning"

}

},

"AllowedHosts": "*",

"ConnectionStrings": {

"MainDB": "Server=localhost;Database=TestDB;Uid=sa;Pwd=123456;", // SQL Server连接字符串

"MySqlDB": "Server=localhost;Database=TestDB_MySQL;Uid=root;Pwd=123456;Port=3306;" // MySQL连接字符串

}

}

读取连接字符串时,可通过IConfiguration接口获取:

复制代码

// 在Program.cs中

var connectionString = builder.Configuration.GetConnectionString("MainDB");

// 在控制器或服务中(需注入IConfiguration)

private readonly IConfiguration _configuration;

public MyService(IConfiguration configuration)

{

_configuration = configuration;

}

public void Test()

{

var connectionString = _configuration.GetConnectionString("MySqlDB");

}

四、实体类映射(ORM 核心)

SQLSugar 通过实体类与数据库表进行映射,实体类的属性对应数据库表的字段。映射方式主要有两种:特性映射 (通过实体类特性指定表名、字段名、主键、自增等)和约定映射(默认约定,如实体类名对应表名、属性名对应字段名)。

4.1 特性映射(推荐)

通过SqlSugar命名空间下的特性(如SugarTable、SugarColumn)明确指定实体类与数据库表的映射关系,灵活性高,适用于表名 / 字段名与实体类 / 属性名不一致的场景。

4.1.1 常用特性说明

|---------------------------------------------|------------------------------------------|
| 特性 | 作用 |
| [SugarTable("表名")] | 指定实体类对应的数据库表名(若不指定,默认实体类名即为表名)。 |
| [SugarColumn(IsPrimaryKey = true)] | 指定该属性为表的主键。 |
| [SugarColumn(IsIdentity = true)] | 指定该属性为自增字段(仅支持整数类型主键)。 |
| [SugarColumn(ColumnName = "字段名")] | 指定属性对应的数据库字段名(若不指定,默认属性名即为字段名)。 |
| [SugarColumn(IsNullable = true/false)] | 指定字段是否允许为 NULL(默认根据属性类型判断,引用类型允许为 NULL)。 |
| [SugarColumn(ColumnDescription = "字段描述")] | 添加字段描述(生成表结构时会同步到数据库表字段的描述中)。 |
| [SugarColumn(IsIgnore = true)] | 忽略该属性,不参与数据库映射(即该属性不会对应表中的任何字段)。 |
| [SugarColumn(Length = 50)] | 指定字段长度(适用于字符串类型,如 VARCHAR (50))。 |

4.1.2 实体类示例

以 "用户表(Users)" 和 "订单表(Orders)" 为例,实体类定义如下:

复制代码

using System;

using SqlSugar;

// 用户表实体类(对应数据库表:Users)

[SugarTable("Users")]

public class User

{

// 主键(自增)

[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "UserId")]

public int Id { get; set; }

// 用户名(字段名:UserName,长度50,非NULL)

[SugarColumn(ColumnName = "UserName", Length = 50, IsNullable = false)]

public string Name { get; set; }

// 年龄(字段名:Age,允许为NULL)

[SugarColumn(ColumnName = "Age", IsNullable = true)]

public int? Age { get; set; }

// 性别(字段名:Gender,长度10,允许为NULL)

[SugarColumn(ColumnName = "Gender", Length = 10, IsNullable = true)]

public string Gender { get; set; }

// 注册时间(字段名:RegisterTime,默认值为当前时间)

[SugarColumn(ColumnName = "RegisterTime", DefaultValue = "GETDATE()")]

public DateTime RegisterTime { get; set; }

// 忽略字段(不映射到数据库表)

[SugarColumn(IsIgnore = true)]

public string TempData { get; set; }

}

// 订单表实体类(对应数据库表:Orders)

[SugarTable("Orders")]

public class Order

{

// 订单ID(主键,自增)

[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "OrderId")]

public int Id { get; set; }

// 用户ID(外键,关联Users表的UserId)

[SugarColumn(ColumnName = "UserId", IsNullable = false)]

public int UserId { get; set; }

// 订单金额(字段名:OrderAmount)

[SugarColumn(ColumnName = "OrderAmount", IsNullable = false)]

public decimal Amount { get; set; }

// 订单状态(字段名:OrderStatus,1:待支付,2:已支付,3:已取消)

[SugarColumn(ColumnName = "OrderStatus", IsNullable = false)]

public int Status { get; set; }

// 订单创建时间(字段名:CreateTime)

[SugarColumn(ColumnName = "CreateTime")]

public DateTime CreateTime { get; set; }

// 导航属性(关联用户表,非数据库字段,需忽略)

[SugarColumn(IsIgnore = true)]

public User User { get; set; }

}

4.2 约定映射(默认)

若数据库表名与实体类名一致、表字段名与实体类属性名一致(大小写不敏感,如 "UserId" 与 "userId" 视为一致),则无需添加任何特性,SQLSugar 会自动完成映射。例如:

复制代码

// 实体类名(User)对应表名(User),属性名(UserId、UserName等)对应字段名(UserId、UserName等)

public class User

{

// 主键(默认识别名为"Id"或"UserId"的属性为主键,若为整数类型,默认自增)

public int UserId { get; set; }

public string UserName { get; set; }

public int? Age { get; set; }

public DateTime RegisterTime { get; set; }

}

4.3 导航属性配置

导航属性用于表示实体类之间的关联关系(如一对一、一对多、多对多),SQLSugar 支持通过导航属性实现关联查询。例如,订单表(Order)与用户表(User)为一对多关系(一个用户可拥有多个订单),可通过以下方式配置导航属性:

复制代码

// 用户表实体类(一对多:一个用户有多个订单)

[SugarTable("Users")]

public class User

{

[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "UserId")]

public int Id { get; set; }

[SugarColumn(ColumnName = "UserName")]

public string Name { get; set; }

// 导航属性:用户的所有订单(一对多)

[SugarColumn(IsIgnore = true)]

public List<Order> Orders { get; set; }

}

// 订单表实体类(多对一:多个订单属于一个用户)

[SugarTable("Orders")]

public class Order

{

[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "OrderId")]

public int Id { get; set; }

[SugarColumn(ColumnName = "UserId")]

public int UserId { get; set; }

[SugarColumn(ColumnName = "OrderAmount")]

public decimal Amount { get; set; }

// 导航属性:订单所属的用户(多对一)

[SugarColumn(IsIgnore = true)]

public User User { get; set; }

}

五、SQLSugar 常见查询举例与对应 SQL 实现

查询是数据库操作中最常用的场景,SQLSugar 提供了Queryable方法构建查询,支持单表查询、多表联查、子查询、分页查询、分组统计等各类查询需求。以下将结合实例,详细讲解常见查询的实现方式,并给出对应的 SQL 语句。

5.1 单表查询

单表查询是最基础的查询场景,主要通过db.Queryable<T>()方法获取查询对象,再结合Where、Select、OrderBy、Take、Skip等方法筛选、排序、限制结果集,最后通过ToList()、FirstOrDefault()等方法执行查询并返回结果。

5.1.1 查询所有数据(无条件)

需求:查询Users表中的所有用户数据。

C# 代码

复制代码

// 方式1:查询所有字段(返回实体类列表)

var allUsers = db.Queryable<User>().ToList();

// 方式2:查询指定字段(返回匿名对象列表)

var userNames = db.Queryable<User>()

.Select(u => new { u.Id, u.Name, u.RegisterTime }) // 指定查询字段

.ToList();

对应 SQL 实现

  • 方式 1 对应 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

  • 方式 2 对应 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [RegisterTime] AS [RegisterTime]

FROM [Users]

5.1.2 根据主键查询单条数据

需求:根据UserId(主键)查询指定用户。

C# 代码

复制代码

// 方式1:使用FindById方法(推荐,仅支持主键查询)

int userId = 1;

var userById = db.Queryable<User>().FindById(userId);

// 方式2:使用Where+FirstOrDefault方法

var userByWhere = db.Queryable<User>()

.Where(u => u.Id == userId) // 主键条件

.FirstOrDefault(); // 返回第一条数据,无数据则返回NULL

对应 SQL 实现

  • 方式 1 / 方式 2 对应 SQL(参数化查询,避免 SQL 注入):
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [UserId] = @Id1 -- @Id1=1

5.1.3 条件查询(单条件 / 多条件)

需求 1:查询年龄大于 20 的用户(单条件)。

C# 代码

复制代码

var usersOver20 = db.Queryable<User>()

.Where(u => u.Age > 20) // 单条件:年龄>20

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [Age] > @Age1 -- @Age1=20

需求 2:查询年龄大于 20 且性别为 "男" 的用户(多条件:AND)。

C# 代码

复制代码

var maleUsersOver20 = db.Queryable<User>()

.Where(u => u.Age > 20 && u.Gender == "男") // 多条件AND

.ToList();

// 或使用Where链式调用(效果相同)

var maleUsersOver20_2 = db.Queryable<User>()

.Where(u => u.Age > 20)

.Where(u => u.Gender == "男")

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [Age] > @Age1 AND [Gender] = @Gender1 -- @Age1=20, @Gender1='男'

需求 3:查询年龄大于 20 或注册时间在 2024 年之后的用户(多条件:OR)。

C# 代码

复制代码

var targetUsers = db.Queryable<User>()

.Where(u => u.Age > 20 || u.RegisterTime >= new DateTime(2024, 1, 1)) // 多条件OR

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [Age] > @Age1 OR [RegisterTime] >= @RegisterTime1 -- @Age1=20, @RegisterTime1='2024-01-01 00:00:00'

5.1.4 模糊查询(Like)

需求:查询用户姓名中包含 "张" 字的用户。

C# 代码

复制代码

// 方式1:使用Contains(自动拼接%,对应LIKE '%张%')

var usersWithZhang = db.Queryable<User>()

.Where(u => u.Name.Contains("张"))

.ToList();

// 方式2:使用StartsWith(对应LIKE '张%')

var usersStartWithZhang = db.Queryable<User>()

.Where(u => u.Name.StartsWith("张"))

.ToList();

// 方式3:使用 EndsWith(对应LIKE '%张')

var usersEndWithZhang = db.Queryable<User>()

.Where(u => u.Name.EndsWith("张"))

.ToList();

// 方式4:手动拼接%(适用于复杂模糊查询场景)

var usersLikeZhang = db.Queryable<User>()

.Where(u => SqlFunc.Like(u.Name, "%张%")) // 使用SqlFunc.Like方法

.ToList();

对应 SQL 实现

  • 方式 1 对应 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [UserName] LIKE @Name1 -- @Name1='%张%'

  • 方式 2 对应 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [UserName] LIKE @Name1 -- @Name1='张%'

  • 方式 3 对应 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [UserName] LIKE @Name1 -- @Name1='%张'

  • 方式 4 对应 SQL(与方式 1 相同):
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [UserName] LIKE @Name1 -- @Name1='%张%'

5.1.5 范围查询(In/Between)

需求 1:查询用户 ID 在 [1,3,5] 范围内的用户(In)。

C# 代码

复制代码

List<int> userIds = new List<int> { 1, 3, 5 };

var usersInIds = db.Queryable<User>()

.Where(u => userIds.Contains(u.Id)) // 使用Contains实现In查询

.ToList();

// 或使用SqlFunc.In方法(效果相同)

var usersInIds_2 = db.Queryable<User>()

.Where(u => SqlFunc.In(u.Id, userIds))

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [UserId] IN (@Id1, @Id2, @Id3) -- @Id1=1, @Id2=3, @Id3=5

需求 2:查询注册时间在 2023 年 1 月 1 日至 2024 年 1 月 1 日之间的用户(Between)。

C# 代码

复制代码

DateTime startDate = new DateTime(2023, 1, 1);

DateTime endDate = new DateTime(2024, 1, 1);

// 方式1:使用>=和<=实现Between

var usersBetweenDate = db.Queryable<User>()

.Where(u => u.RegisterTime >= startDate && u.RegisterTime <= endDate)

.ToList();

// 方式2:使用SqlFunc.Between方法

var usersBetweenDate_2 = db.Queryable<User>()

.Where(u => SqlFunc.Between(u.RegisterTime, startDate, endDate))

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

WHERE [RegisterTime] BETWEEN @RegisterTime1 AND @RegisterTime2 -- @RegisterTime1='2023-01-01 00:00:00', @RegisterTime2='2024-01-01 00:00:00'

5.1.6 排序查询(OrderBy)

需求:查询所有用户,先按注册时间降序排序(最新注册的在前),再按年龄升序排序(年龄小的在前)。

C# 代码

复制代码

var sortedUsers = db.Queryable<User>()

.OrderBy(u => u.RegisterTime, OrderByType.Desc) // 降序排序(Desc)

.OrderBy(u => u.Age, OrderByType.Asc) // 升序排序(Asc,默认可省略)

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

ORDER BY [RegisterTime] DESC, [Age] ASC

5.1.7 限制结果集(Take/Skip)

需求 1:查询前 10 条用户数据(Take)。

C# 代码

复制代码

var top10Users = db.Queryable<User>()

.Take(10) // 取前10条

.ToList();

对应 SQL(SQL Server)

复制代码

SELECT TOP 10 [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

对应 SQL(MySQL)

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

LIMIT 10

需求 2:跳过前 5 条数据,查询后续的 10 条数据(Skip+Take,常用于分页的基础)。

C# 代码

复制代码

var skip5Take10Users = db.Queryable<User>()

.Skip(5) // 跳过前5条

.Take(10) // 取后续10条

.ToList();

对应 SQL(SQL Server)

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM (

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime],

ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS RowNum -- 临时排序字段

FROM [Users]

) AS Temp

WHERE Temp.RowNum > 5 AND Temp.RowNum <= 15 -- 5+10=15

对应 SQL(MySQL)

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

LIMIT 5, 10 -- 跳过5条,取10条(偏移量5,条数10)

5.1.8 分页查询

分页查询是项目中常用的查询场景,SQLSugar 提供了ToPageList方法,直接支持分页,无需手动计算Skip和Take,同时可获取总记录数。

需求:查询用户列表,每页显示 10 条数据,查询第 2 页的数据,并获取总记录数。

C# 代码

复制代码

int pageIndex = 2; // 当前页码(从1开始)

int pageSize = 10; // 每页条数

int totalCount = 0; // 总记录数(输出参数)

// 方式1:使用ToPageList方法(推荐,自动计算分页,并返回总记录数)

var userPageList = db.Queryable<User>()

.OrderBy(u => u.RegisterTime, OrderByType.Desc) // 分页必须排序,否则结果不稳定

.ToPageList(pageIndex, pageSize, ref totalCount);

// 方式2:手动计算Skip和Take(适用于复杂场景)

var userPageList_2 = db.Queryable<User>()

.OrderBy(u => u.RegisterTime, OrderByType.Desc)

.Skip((pageIndex - 1) * pageSize) // 计算跳过的条数:(页码-1)*每页条数

.Take(pageSize)

.ToList();

// 手动获取总记录数

totalCount = db.Queryable<User>().Count();

Console.WriteLine($"总记录数:{totalCount}");

Console.WriteLine($"第{pageIndex}页数据条数:{userPageList.Count}");

对应 SQL(SQL Server,方式 1)

  • 查询分页数据的 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM (

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime],

ROW_NUMBER() OVER (ORDER BY [RegisterTime] DESC) AS RowNum

FROM [Users]

) AS Temp

WHERE Temp.RowNum > 10 AND Temp.RowNum <= 20 -- (2-1)*10=10,2*10=20

  • 获取总记录数的 SQL:
复制代码

SELECT COUNT(1) FROM [Users]

对应 SQL(MySQL,方式 1)

  • 查询分页数据的 SQL:
复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users]

ORDER BY [RegisterTime] DESC

LIMIT 10, 10 -- (2-1)*10=10(偏移量),10(条数)

  • 获取总记录数的 SQL:
复制代码

SELECT COUNT(1) FROM [Users]

5.1.9 统计查询(Count/Sum/Avg/Max/Min)

需求 1:统计Users表中的总用户数(Count)。

C# 代码

复制代码

// 方式1:统计所有记录数

int totalUserCount = db.Queryable<User>().Count();

// 方式2:统计满足条件的记录数(年龄>20的用户数)

int userCountOver20 = db.Queryable<User>()

.Where(u => u.Age > 20)

.Count();

对应 SQL

  • 方式 1:SELECT COUNT(1) FROM [Users]
  • 方式 2:SELECT COUNT(1) FROM [Users] WHERE [Age] > @Age1(@Age1=20)

需求 2:统计所有订单的总金额(Sum)、平均金额(Avg)、最大金额(Max)、最小金额(Min)。

C# 代码

复制代码

// 总金额(Sum)

decimal totalAmount = db.Queryable<Order>().Sum(o => o.Amount);

// 平均金额(Avg,返回double类型)

double avgAmount = db.Queryable<Order>().Avg(o => o.Amount);

// 最大金额(Max)

decimal maxAmount = db.Queryable<Order>().Max(o => o.Amount);

// 最小金额(Min)

decimal minAmount = db.Queryable<Order>().Min(o => o.Amount);

// 若结果可能为NULL(如表中无数据),建议使用可空类型接收

decimal? totalAmountNullable = db.Queryable<Order>().Sum<decimal?>(o => o.Amount);

对应 SQL

  • 总金额:SELECT SUM([OrderAmount]) FROM [Orders]
  • 平均金额:SELECT AVG(CAST([OrderAmount] AS FLOAT)) FROM [Orders](SQL Server 中需转换类型)
  • 最大金额:SELECT MAX([OrderAmount]) FROM [Orders]
  • 最小金额:SELECT MIN([OrderAmount]) FROM [Orders]
5.1.10 分组统计查询(GroupBy)

需求:按用户 ID 分组,统计每个用户的订单数量和订单总金额。

C# 代码

复制代码

// 分组统计:按UserId分组,统计订单数和总金额

var userOrderStats = db.Queryable<Order>()

.GroupBy(o => o.UserId) // 按UserId分组

.Select(o => new

{

UserId = o.UserId,

OrderCount = SqlFunc.AggregateCount(o.Id), // 统计订单数

TotalAmount = SqlFunc.AggregateSum(o.Amount) // 统计总金额

})

.ToList();

// 筛选分组结果:仅显示订单数>=2的用户

var userOrderStatsFiltered = db.Queryable<Order>()

.GroupBy(o => o.UserId)

.Having(o => SqlFunc.AggregateCount(o.Id) >= 2) // 分组后筛选(Having)

.Select(o => new

{

UserId = o.UserId,

OrderCount = SqlFunc.AggregateCount(o.Id),

TotalAmount = SqlFunc.AggregateSum(o.Amount)

})

.ToList();

对应 SQL

  • 未筛选分组结果:
复制代码

SELECT [UserId] AS [UserId],

COUNT([OrderId]) AS [OrderCount],

SUM([OrderAmount]) AS [TotalAmount]

FROM [Orders]

GROUP BY [UserId]

  • 筛选分组结果(Having):
复制代码

SELECT [UserId] AS [UserId],

COUNT([OrderId]) AS [OrderCount],

SUM([OrderAmount]) AS [TotalAmount]

FROM [Orders]

GROUP BY [UserId]

HAVING COUNT([OrderId]) >= @Count1 -- @Count1=2

5.2 多表联查

多表联查用于查询多个关联表的数据,SQLSugar 支持Join方法实现内联(Inner Join)、左联(Left Join)、右联(Right Join)、全联(Full Join)等联查方式,联查条件通过On方法指定。

5.2.1 两表联查(左联:Left Join)

需求:查询所有用户及其关联的订单信息(若用户无订单,订单信息为 NULL)。

C# 代码

复制代码

// 方式1:使用Join方法(Left Join)

var userOrderLeftJoin = db.Queryable<User>()

.LeftJoin<Order>((u, o) => u.Id == o.UserId) // 左联Orders表,联查条件:u.Id = o.UserId

.Select((u, o) => new

{

UserId = u.Id,

UserName = u.Name,

OrderId = o.Id,

OrderAmount = o.Amount,

OrderStatus = o.Status

})

.ToList();

// 方式2:通过导航属性联查(简化代码,需先配置导航属性)

var userOrderNav = db.Queryable<User>()

.Include(u => u.Orders) // 加载用户的Orders导航属性(左联)

.ToList();

对应 SQL(方式 1)

复制代码

SELECT

u.[UserId] AS [UserId],

u.[UserName] AS [UserName],

o.[OrderId] AS [OrderId],

o.[OrderAmount] AS [OrderAmount],

o.[OrderStatus] AS [OrderStatus]

FROM [Users] u

LEFT JOIN [Orders] o ON u.[UserId] = o.[UserId]

5.2.2 两表联查(内联:Inner Join)

需求:查询有订单的用户及其订单信息(仅返回同时存在于 Users 和 Orders 表中的数据)。

C# 代码

复制代码

var userOrderInnerJoin = db.Queryable<User>()

.InnerJoin<Order>((u, o) => u.Id == o.UserId) // 内联Orders表

.Select((u, o) => new

{

UserId = u.Id,

UserName = u.Name,

OrderId = o.Id,

OrderAmount = o.Amount

})

.ToList();

对应 SQL

复制代码

SELECT

u.[UserId] AS [UserId],

u.[UserName] AS [UserName],

o.[OrderId] AS [OrderId],

o.[OrderAmount] AS [OrderAmount]

FROM [Users] u

INNER JOIN [Orders] o ON u.[UserId] = o.[UserId]

5.2.3 三表联查(左联 + 内联)

需求:假设有Users(用户表)、Orders(订单表)、OrderDetails(订单详情表),查询用户、订单及对应的订单详情信息(左联订单表,内联订单详情表)。

实体类补充

复制代码

[SugarTable("OrderDetails")]

public class OrderDetail

{

[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "DetailId")]

public int Id { get; set; }

[SugarColumn(ColumnName = "OrderId")]

public int OrderId { get; set; }

[SugarColumn(ColumnName = "ProductName", Length = 100)]

public string ProductName { get; set; }

[SugarColumn(ColumnName = "ProductPrice")]

public decimal ProductPrice { get; set; }

[SugarColumn(ColumnName = "Quantity")]

public int Quantity { get; set; }

// 导航属性

[SugarColumn(IsIgnore = true)]

public Order Order { get; set; }

}

C# 代码

复制代码

var userOrderDetailJoin = db.Queryable<User>()

.LeftJoin<Order>((u, o) => u.Id == o.UserId) // 左联Orders表

.InnerJoin<OrderDetail>((u, o, od) => o.Id == od.OrderId) // 内联OrderDetails表

.Select((u, o, od) => new

{

UserId = u.Id,

UserName = u.Name,

OrderId = o.Id,

OrderAmount = o.Amount,

ProductName = od.ProductName,

ProductPrice = od.ProductPrice,

Quantity = od.Quantity

})

.ToList();

对应 SQL

复制代码

SELECT

u.[UserId] AS [UserId],

u.[UserName] AS [UserName],

o.[OrderId] AS [OrderId],

o.[OrderAmount] AS [OrderAmount],

od.[ProductName] AS [ProductName],

od.[ProductPrice] AS [ProductPrice],

od.[Quantity] AS [Quantity]

FROM [Users] u

LEFT JOIN [Orders] o ON u.[UserId] = o.[UserId]

INNER JOIN [OrderDetails] od ON o.[OrderId] = od.[OrderId]

5.3 子查询

子查询(嵌套查询)是指在一个查询语句内部包含另一个查询语句,SQLSugar 支持通过Queryable嵌套实现子查询,适用于复杂的查询场景。

5.3.1 子查询作为条件(Exists/In)

需求 1:查询存在订单的用户(使用 Exists 子查询)。

C# 代码

复制代码

var usersWithOrders = db.Queryable<User>()

.Where(u => db.Queryable<Order>()

.Any(o => o.UserId == u.Id)) // Any对应Exists:判断是否存在满足条件的订单

.ToList();

对应 SQL

复制代码

SELECT [UserId] AS [Id], [UserName] AS [Name], [Age] AS [Age], [Gender] AS [Gender], [RegisterTime] AS [RegisterTime]

FROM [Users] u

WHERE EXISTS (

SELECT 1 FROM [Orders] o WHERE o.[UserId] = u.[UserId]

)

需求 2:查询订单金额大于平均订单金额的订单(使用子查询获取平均金额)。

C# 代码

复制代码

// 子查询:获取平均订单金额

var ordersOverAvgAmount = db.Queryable<Order>()

.Where(o => o.Amount > db.Queryable<Order>()

.Avg<decimal?>(o2 => o2.Amount)) // 子查询获取平均金额

.ToList();

对应 SQL

复制代码

SELECT [OrderId] AS [Id], [UserId] AS [UserId], [OrderAmount] AS [Amount], [OrderStatus] AS [Status], [CreateTime] AS [CreateTime]

FROM [Orders] o

WHERE o.[OrderAmount] > (

SELECT AVG([OrderAmount]) FROM [Orders]

)

5.3.2 子查询作为结果集(From 子查询)

需求:查询每个用户的最新订单(先按用户分组获取最新订单 ID,再关联订单表查询详情)。

C# 代码

复制代码

// 子查询:按用户分组,获取每个用户的最新订单ID(最大OrderId)

var subQuery = db.Queryable<Order>()

.GroupBy(o => o.UserId)

.Select(o => new { UserId = o.UserId, MaxOrderId = SqlFunc.AggregateMax(o.Id) });

// 主查询:关联子查询和订单表,获取最新订单详情

var latestOrders = db.Queryable(subQuery, "sub") // 子查询作为临时表,别名sub

.InnerJoin<Order>((sub, o) => sub.MaxOrderId == o.Id) // 关联订单表

.Select((sub, o) => new

{

UserId = sub.UserId,

OrderId = o.Id,

OrderAmount = o.Amount,

CreateTime = o.CreateTime

})

.ToList();

对应 SQL

复制代码

SELECT

sub.[UserId] AS [UserId],

o.[OrderId] AS [OrderId],

o.[OrderAmount] AS [OrderAmount],

o.[CreateTime] AS [CreateTime]

FROM (

SELECT [UserId] AS [UserId], MAX([OrderId]) AS [MaxOrderId]

FROM [Orders]

GROUP BY [UserId]

) sub

INNER JOIN [Orders] o ON sub.[MaxOrderId] = o.[OrderId]

5.4 自定义 SQL 查询

对于特别复杂的查询场景(如多表嵌套、特殊函数调用等),若通过Queryable方法难以实现,可直接使用 SQLSugar 的自定义 SQL 查询功能,通过Ado.SqlQuery或Ado.SqlQuerySingle方法执行原生 SQL 语句。

5.4.1 执行查询 SQL(返回实体类 / 匿名对象)

需求:通过自定义 SQL 查询用户及其订单数量。

C# 代码

复制代码

// 方式1:返回匿名对象(适用于无需定义实体类的场景)

string sql = @"

SELECT

u.UserId AS Id,

u.UserName AS Name,

COUNT(o.OrderId) AS OrderCount

FROM Users u

LEFT JOIN Orders o ON u.UserId = o.UserId

GROUP BY u.UserId, u.UserName

";

var userOrderCount = db.Ado.SqlQuery<dynamic>(sql); // dynamic类型接收匿名对象

// 方式2:返回实体类(需定义对应实体类)

// 定义接收结果的实体类

public class UserOrderCountDto

{

public int Id { get; set; }

public string Name { get; set; }

public int OrderCount { get; set; }

}

var userOrderCountDto = db.Ado.SqlQuery<UserOrderCountDto>(sql);

对应 SQL:与自定义 SQL 语句一致。

5.4.2 带参数的自定义 SQL(防止 SQL 注入)

需求:通过自定义 SQL 查询指定用户 ID 的订单信息(带参数)。

C# 代码

复制代码

int targetUserId = 1;

string sqlWithParam = @"

SELECT

OrderId AS Id,

UserId,

OrderAmount AS Amount,

OrderStatus AS Status

FROM Orders

WHERE UserId = @UserId

";

// 方式1:使用匿名对象传递参数

var ordersByUserId1 = db.Ado.SqlQuery<Order>(sqlWithParam, new { UserId = targetUserId });

// 方式2:使用SugarParameter传递参数(适用于复杂参数场景)

var param = new SugarParameter("@UserId", targetUserId);

var ordersByUserId2 = db.Ado.SqlQuery<Order>(sqlWithParam, param);

对应 SQL

复制代码

SELECT

OrderId AS Id,

UserId,

OrderAmount AS Amount,

OrderStatus AS Status

FROM Orders

WHERE UserId = @UserId -- @UserId=1

六、SQLSugar 详细使用指导

6.1 CRUD 操作完整示例(除查询外)

除了查询操作,SQLSugar 还提供了简洁的 API 实现新增(Create)、修改(Update)、删除(Delete)操作,以下结合实例讲解。

6.1.1 新增操作(Insert)

需求 1:新增单个用户。

C# 代码

复制代码

var newUser = new User

{

Name = "李四",

Age = 25,

Gender = "男",

RegisterTime = DateTime.Now

};

// 方式1:新增并返回自增主键(适用于自增主键场景)

int newUserId = db.Insertable(newUser).ExecuteReturnIdentity(); // 返回新增用户的Id(自增主键)

// 方式2:新增并返回受影响行数(适用于非自增主键场景)

int affectedRows = db.Insertable(newUser).ExecuteCommand(); // 返回受影响的行数(1表示成功)

对应 SQL

复制代码

INSERT INTO [Users] ([UserName], [Age], [Gender], [RegisterTime])

VALUES (@UserName1, @Age1, @Gender1, @RegisterTime1);

SELECT SCOPE_IDENTITY() AS [Id] -- SQL Server获取自增主键;MySQL为SELECT LAST_INSERT_ID()

需求 2:批量新增用户(高效,减少数据库交互次数)。

C# 代码

复制代码

var userList = new List<User>

{

new User { Name = "王五", Age = 22, Gender = "女", RegisterTime = DateTime.Now },

new User { Name = "赵六", Age = 30, Gender = "男", RegisterTime = DateTime.Now },

new User { Name = "孙七", Age = 28, Gender = "女", RegisterTime = DateTime.Now }

};

// 批量新增(支持批量插入,自动优化SQL)

int totalAffectedRows = db.Insertable(userList).ExecuteCommand(); // 返回总受影响行数(3表示成功)

对应 SQL(SQL Server,批量插入优化)

复制代码

INSERT INTO [Users] ([UserName], [Age], [Gender], [RegisterTime])

VALUES

(@UserName1, @Age1, @Gender1, @RegisterTime1),

(@UserName2, @Age2, @Gender2, @RegisterTime2),

(@UserName3, @Age3, @Gender3, @RegisterTime3)

6.1.2 修改操作(Update)

需求 1:修改单个用户信息(根据主键)。

C# 代码

复制代码

var updateUser = new User

{

Id = 1, // 主键(必须指定,用于定位要修改的记录)

Name = "李四_修改", // 要修改的字段

Age = 26 // 要修改的字段

};

// 方式1:修改所有非NULL字段(默认)

int affectedRows1 = db.Updateable(updateUser).ExecuteCommand();

// 方式2:指定修改的字段(忽略其他字段)

int affectedRows2 = db.Updateable(updateUser)

.SetColumns(u => new User { Name = u.Name, Age = u.Age }) // 仅修改Name和Age字段

.ExecuteCommand();

// 方式3:根据条件修改(不依赖实体类主键)

int affectedRows3 = db.Updateable<User>()

.SetColumns(u => u.Age == 26) // 修改字段:Age=26

.Where(u => u.Id == 1) // 条件:Id=1

.ExecuteCommand();

对应 SQL

  • 方式 1 / 方式 2:
复制代码

UPDATE [Users]

SET [UserName] = @UserName1, [Age] = @Age1

WHERE [UserId] = @Id1 -- @Id1=1, @UserName1='李四_修改', @Age1=26

  • 方式 3:
复制代码

UPDATE [Users]

SET [Age] = @Age1

WHERE [UserId] = @Id1 -- @Id1=1, @Age1=26

需求 2:批量修改订单状态(将用户 ID 为 1 的所有订单状态改为 "已支付")。

C# 代码

复制代码

int targetUserId = 1;

int newStatus = 2; // 2:已支付

int affectedRows = db.Updateable<Order>()

.SetColumns(o => o.Status == newStatus)

.Where(o => o.UserId == targetUserId)

.ExecuteCommand();

对应 SQL

复制代码

UPDATE [Orders]

SET [OrderStatus] = @Status1

WHERE [UserId] = @UserId1 -- @Status1=2, @UserId1=1

6.1.3 删除操作(Delete)

需求 1:根据主键删除单个用户。

C# 代码

复制代码

int targetUserId = 1;

// 方式1:根据实体类主键删除

var deleteUser = new User { Id = targetUserId };

int affectedRows1 = db.Deleteable(deleteUser).ExecuteCommand();

// 方式2:直接根据主键值删除

int affectedRows2 = db.Deleteable<User>().In(targetUserId).ExecuteCommand();

// 方式3:根据条件删除

int affectedRows3 = db.Deleteable<User>()

.Where(u => u.Id == targetUserId)

.ExecuteCommand();

对应 SQL

复制代码

DELETE FROM [Users] WHERE [UserId] = @Id1 -- @Id1=1

需求 2:批量删除用户(根据用户 ID 列表)。

C# 代码

复制代码

List<int> deleteUserIds = new List<int> { 2, 3, 4 };

// 批量删除(In查询)

int affectedRows = db.Deleteable<User>().In(deleteUserIds).ExecuteCommand();

对应 SQL

复制代码

DELETE FROM [Users] WHERE [UserId] IN (@Id1, @Id2, @Id3) -- @Id1=2, @Id2=3, @Id3=4

6.2 事务处理

事务用于保证一组数据库操作的原子性(要么全部成功,要么全部失败),SQLSugar 支持手动事务和自动事务两种方式。

6.2.1 手动事务(推荐,灵活控制)

需求:新增用户的同时,为该用户创建一条初始订单,若其中一个操作失败,回滚所有操作。

C# 代码

复制代码

try

{

// 1. 开启事务

db.Ado.BeginTran();

// 2. 执行新增用户操作

var newUser = new User { Name = "钱八", Age = 24, Gender = "男", RegisterTime = DateTime.Now };

int newUserId = db.Insertable(newUser).ExecuteReturnIdentity();

// 3. 执行新增订单操作(关联新用户ID)

var newOrder = new Order

{

UserId = newUserId,

Amount = 100.50m,

Status = 1, // 1:待支付

CreateTime = DateTime.Now

};

db.Insertable(newOrder).ExecuteCommand();

// 4. 提交事务(所有操作成功,提交)

db.Ado.CommitTran();

Console.WriteLine("事务执行成功!");

}

catch (Exception ex)

{

// 5. 回滚事务(若有操作失败,回滚)

db.Ado.RollbackTran();

Console.WriteLine($"事务执行失败,已回滚:{ex.Message}");

}

6.2.2 自动事务(简化代码,通过特性或方法)

需求 :在ASP.NET Core 控制器中,通过特性自动开启事务。

C# 代码

复制代码

// 1. 注册事务服务(Program.cs)

builder.Services.AddSqlSugarTransaction();

// 2. 在控制器方法中使用[Transaction]特性

[ApiController]

[Route("api/[controller]")]

public class UserController : ControllerBase

{

private readonly ISqlSugarClient _db;

public UserController(ISqlSugarClient db)

{

_db = db;

}

[HttpPost("AddUserAndOrder")]

[Transaction] // 自动开启事务,方法执行成功自动提交,失败自动回滚

public IActionResult AddUserAndOrder(User user, Order order)

{

// 新增用户

int newUserId = _db.Insertable(user).ExecuteReturnIdentity();

// 新增订单

order.UserId = newUserId;

_db.Insertable(order).ExecuteCommand();

return Ok("操作成功!");

}

}

6.3 缓存功能

SQLSugar 提供了内置缓存功能,支持将查询结果缓存到内存中,减少数据库查询次数,提升系统性能。缓存默认使用内存缓存,也支持自定义缓存(如 Redis)。

6.3.1 基础缓存使用(内存缓存)

需求:查询用户列表并缓存 10 分钟,10 分钟内再次查询时直接从缓存获取。

C# 代码

复制代码

// 方式1:使用WithCache方法设置缓存(缓存Key自动生成)

var userList1 = db.Queryable<User>()

.WithCache(600) // 缓存时间:600秒(10分钟)

.ToList();

// 方式2:自定义缓存Key(便于手动清除缓存)

string cacheKey = "UserList_CacheKey";

var userList2 = db.Queryable<User>()

.WithCache(600, cacheKey) // 自定义缓存Key

.ToList();

// 手动清除缓存(当数据更新时,需清除对应缓存)

db.CacheService.Remove(cacheKey); // 清除指定Key的缓存

// db.CacheService.Clear(); // 清除所有缓存

6.3.2 自定义 Redis 缓存

需求:将查询结果缓存到 Redis 中,适用于分布式系统。

C# 代码

复制代码

// 1. 实现ICacheService接口(Redis缓存实现)

public class RedisCacheService : ICacheService

{

private readonly IDistributedCache _redisCache;

public RedisCacheService(IDistributedCache redisCache)

{

_redisCache = redisCache;

}

// 添加缓存

public void Add<V>(string key, V value, int cacheDurationInSeconds)

{

var options = new DistributedCacheEntryOptions

{

AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(cacheDurationInSeconds)

};

string jsonValue = JsonSerializer.Serialize(value);

_redisCache.SetString(key, jsonValue, options);

}

// 获取缓存

public V Get<V>(string key)

{

string jsonValue = _redisCache.GetString(key);

return string.IsNullOrEmpty(jsonValue) ? default : JsonSerializer.Deserialize<V>(jsonValue);

}

// 移除缓存

public void Remove(string key)

{

_redisCache.Remove(key);

}

// 清除所有缓存(Redis不建议批量清除,可根据实际需求实现)

public void Clear()

{

// Redis批量清除需通过KEYS命令,生产环境慎用,此处省略实现

}

}

// 2. 注册Redis缓存服务(Program.cs)

builder.Services.AddStackExchangeRedisCache(options =>

{

options.Configuration = "localhost:6379"; // Redis连接字符串

});

builder.Services.AddScoped<ICacheService, RedisCacheService>();

// 3. 使用Redis缓存查询

var userList = db.Queryable<User>()

.WithCache(600, "UserList_RedisKey") // 使用Redis缓存

.ToList();

6.4 代码生成器

SQLSugar 提供了代码生成器功能,可根据数据库表结构自动生成实体类、仓储类、服务类等代码,减少重复编码工作,提升开发效率。

6.4.1 基础代码生成(生成实体类)

C# 代码

复制代码

// 1. 创建代码生成器配置

var codeConfig = new CodeGeneratorConfig

{

ConnectionString = "Server=localhost;Database=TestDB;Uid=sa;Pwd=123456;",

DbType = DbType.SqlServer,

OutputDir = @"D:\CodeGeneratorOutput", // 代码输出目录

Namespace = "TestProject.Entities", // 实体类命名空间

GenerateNullableReferenceType = true, // 生成可空引用类型(.NET 6+支持)

EntityNameFormat = "{0}", // 实体类名格式({0}表示表名)

ColumnNameFormat = "{0}" // 属性名格式({0}表示字段名)

};

// 2. 创建代码生成器

var codeGenerator = new CodeGenerator(codeConfig);

// 3. 生成实体类(生成所有表的实体类)

codeGenerator.GenerateEntities();

// 4. (可选)生成指定表的实体类

codeGenerator.GenerateEntities(new List<string> { "Users", "Orders" }); // 仅生成Users和Orders表的实体类

Console.WriteLine("代码生成完成!");

6.4.2 高级代码生成(生成仓储类 + 服务类)

C# 代码

复制代码

// 配置代码生成器

var codeConfig = new CodeGeneratorConfig

{

ConnectionString = "Server=localhost;Database=TestDB;Uid=sa;Pwd=123456;",

DbType = DbType.SqlServer,

OutputDir = @"D:\CodeGeneratorOutput",

Namespace = "TestProject",

// 生成仓储类(Repository)

GenerateRepository = true,

RepositoryNamespace = "TestProject.Repositories",

// 生成服务类(Service)

GenerateService = true,

ServiceNamespace = "TestProject.Services"

};

var codeGenerator = new CodeGenerator(codeConfig);

// 生成实体类、仓储类、服务类

codeGenerator.GenerateAll(); // 生成所有支持的代码类型

Console.WriteLine("所有代码生成完成!");

七、SQLSugar 使用注意事项

7.1 连接与性能相关

  1. 自动关闭连接:初始化SqlSugarClient时,务必将IsAutoCloseConnection设置为true,避免数据库连接泄露。若设置为false,需手动调用db.Close()关闭连接。
  1. SqlSugarClient 实例生命周期
    • 非 IOC 模式:建议每个请求创建一个SqlSugarClient实例,使用完毕后自动关闭(依赖IsAutoCloseConnection=true),避免单例实例导致的线程安全问题。
    • IOC 模式:在ASP.NET Core 中,推荐使用Scoped生命周期(每个请求一个实例),避免Singleton(单例)导致的线程安全问题。
  1. 批量操作优化:批量新增、修改、删除时,使用 SQLSugar 提供的批量 API(如Insertable<List<T>>、Updateable<T>.In),避免循环调用单条操作,减少数据库交互次数。
  1. 避免过度查询:查询时仅获取需要的字段(使用Select指定字段),避免Select *查询不必要的字段,减少数据传输量和数据库负担。

7.2 实体类映射相关

  1. 主键与自增配置
    • 主键必须通过[SugarColumn(IsPrimaryKey = true)]明确指定,否则 SQLSugar 无法识别主键,导致修改、删除操作失败。
    • 自增字段需同时设置IsIdentity = true,且字段类型必须为整数类型(int、long 等),非整数类型无法支持自增。
  1. 字段类型匹配:实体类属性类型需与数据库表字段类型匹配,例如:
    • 数据库中的VARCHAR/NVARCHAR类型对应 C# 中的string类型。
    • 数据库中的DECIMAL类型对应 C# 中的decimal类型(避免使用double,防止精度丢失)。
    • 数据库中的DATETIME/DATETIME2类型对应 C# 中的DateTime类型。
  1. 导航属性忽略:导航属性(如User.Orders、Order.User)仅用于关联查询,不对应数据库表字段,需通过[SugarColumn(IsIgnore = true)]标记为忽略,否则会导致映射错误。
  1. 表名 / 字段名大小写:SQLSugar 默认不区分表名和字段名的大小写(如 "Users" 与 "users" 视为一致),但部分数据库(如 MySQL)默认区分大小写,需确保实体类特性指定的表名 / 字段名与数据库一致。

7.3 查询相关

  1. 分页必须排序:使用ToPageList进行分页查询时,必须通过OrderBy指定排序字段,否则数据库返回的结果顺序不稳定,导致分页数据重复或缺失。
  1. 子查询性能:复杂子查询可能导致性能问题,建议优先使用联查(Join)替代子查询,或通过索引优化子查询条件字段。
  1. 模糊查询优化:使用Like '%关键词%'(对应Contains)会导致索引失效,若需优化性能,可考虑:
    • 使用Like '关键词%'(对应StartsWith),可利用字段的前缀索引。