目录
2.1.1 通过 Visual Studio NuGet 图形化界面安装
3.2 IOC 模式初始化(适用于ASP.NET Core)
3.2.1 配置服务(Program.cs/.NET 6+)
5.1.9 统计查询(Count/Sum/Avg/Max/Min)
一、SQLSugar 简介
SQLSugar 是一款轻量级、高性能的 ORM(对象关系映射)框架,基于.NET 平台开发,支持多种数据库(如 SQL Server、MySQL、Oracle、SQLite、PostgreSQL 等)。它兼具了 EF(Entity Framework)的易用性和 Dapper 的高性能,提供了丰富的 API 接口,能轻松实现数据库的增删改查(CRUD)操作,同时支持复杂查询、事务处理、代码优先(Code First)、数据库优先(DB First)等功能,是.NET 开发者在项目开发中操作数据库的优质选择。
相比其他 ORM 框架,SQLSugar 具有以下优势:
- 性能优异:采用了高效的 SQL 生成机制和参数化查询,避免 SQL 注入问题,同时减少数据库交互次数,提升查询效率。
- 易用性强:API 设计简洁直观,学习成本低,开发者无需编写复杂的 SQL 语句,通过面向对象的方式即可操作数据库。
- 功能全面:支持单表查询、多表联查、子查询、分组统计、分页查询等各类查询场景,同时提供事务、缓存、日志、代码生成等辅助功能。
- 多数据库支持:只需修改连接字符串和数据库类型配置,即可在不同数据库之间无缝切换,降低项目的数据库迁移成本。
- 扩展性好:支持自定义 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 图形化界面安装
- 打开 Visual Studio,创建或打开一个.NET 项目(如控制台应用、ASP.NET Core Web 应用等)。
- 在 “解决方案资源管理器” 中,右键点击项目名称,选择 “管理 NuGet 程序包”。
- 在弹出的 NuGet 包管理器界面中,切换到 “浏览” 选项卡,在搜索框中输入 “SQLSugar”。
- 找到 “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 连接与性能相关
- 自动关闭连接:初始化SqlSugarClient时,务必将IsAutoCloseConnection设置为true,避免数据库连接泄露。若设置为false,需手动调用db.Close()关闭连接。
- SqlSugarClient实例生命周期:
-
- 非 IOC 模式:建议每个请求创建一个SqlSugarClient实例,使用完毕后自动关闭(依赖IsAutoCloseConnection=true),避免单例实例导致的线程安全问题。
-
- IOC 模式:在ASP.NET Core 中,推荐使用Scoped生命周期(每个请求一个实例),避免Singleton(单例)导致的线程安全问题。
- 批量操作优化:批量新增、修改、删除时,使用 SQLSugar 提供的批量 API(如Insertable<List<T>>、Updateable<T>.In),避免循环调用单条操作,减少数据库交互次数。
- 避免过度查询:查询时仅获取需要的字段(使用Select指定字段),避免Select *查询不必要的字段,减少数据传输量和数据库负担。
7.2 实体类映射相关
- 主键与自增配置:
-
- 主键必须通过[SugarColumn(IsPrimaryKey = true)]明确指定,否则 SQLSugar 无法识别主键,导致修改、删除操作失败。
-
- 自增字段需同时设置IsIdentity = true,且字段类型必须为整数类型(int、long 等),非整数类型无法支持自增。
- 字段类型匹配:实体类属性类型需与数据库表字段类型匹配,例如:
-
- 数据库中的VARCHAR/NVARCHAR类型对应 C# 中的string类型。
-
- 数据库中的DECIMAL类型对应 C# 中的decimal类型(避免使用double,防止精度丢失)。
-
- 数据库中的DATETIME/DATETIME2类型对应 C# 中的DateTime类型。
- 导航属性忽略:导航属性(如User.Orders、Order.User)仅用于关联查询,不对应数据库表字段,需通过[SugarColumn(IsIgnore = true)]标记为忽略,否则会导致映射错误。
- 表名 / 字段名大小写:SQLSugar 默认不区分表名和字段名的大小写(如 “Users” 与 “users” 视为一致),但部分数据库(如 MySQL)默认区分大小写,需确保实体类特性指定的表名 / 字段名与数据库一致。
7.3 查询相关
- 分页必须排序:使用ToPageList进行分页查询时,必须通过OrderBy指定排序字段,否则数据库返回的结果顺序不稳定,导致分页数据重复或缺失。
- 子查询性能:复杂子查询可能导致性能问题,建议优先使用联查(Join)替代子查询,或通过索引优化子查询条件字段。
- 模糊查询优化:使用Like '%关键词%'(对应Contains)会导致索引失效,若需优化性能,可考虑:
-
- 使用Like '关键词%'(对应StartsWith),可利用字段的前缀索引。