简介
在构建 SaaS 平台、中台系统或需要频繁动态扩展业务实体的项目中,传统的静态编译实体映射已无法满足需求。SqlSugar 作为国产优秀的 ORM 框架,凭借其强大的 DynamicBuilder(动态构建)和 Multi-Tenancy(多租户/多库)支持,成为了此类场景下的首选方案。
本文将深入探讨如何利用 SqlSugar 在运行时动态创建表、维护多库环境、实现跨库联表查询,以及应用全局过滤器保障数据安全。
1. 动态建模与 CodeFirst 演进
SqlSugar 的 CodeFirst 能够根据 C# 类自动同步数据库表结构。除了基础的特性建模,它还支持完全脱离物理类的“动态建模”。
1.1 场景一:基于特性的标准建模
这是最常用的方式,适合业务相对固定的模块。通过特性定义字段元数据,确保跨数据库(MySQL/SQLServer/Oracle)的行为一致。
[SugarTable("Base_User")]
public class UserEntity
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
[SugarColumn(ColumnDescription = "用户名", Length = 50)]
public string Name { get; set; }
[SugarColumn(IsNullable = true, DefaultValue = "getdate()")]
public DateTime CreateTime { get; set; }
}
// 一键同步/创建表
db.CodeFirst.InitTables(typeof(UserEntity));
1.2 场景二:运行时动态创建类 (DynamicBuilder)
应用场景:用户自定义表单、低代码平台。你不需要预先写好 .cs 文件,可以在程序运行时根据配置文件生成表。
var dynamicType = db.DynamicBuilder()
.CreateClass("Custom_Report_001", new SugarTable())
.CreateProperty("Id", typeof(int), new SugarColumn() { IsPrimaryKey = true, IsIdentity = true })
.CreateProperty("ExtData", typeof(string), new SugarColumn() { Length = 1000 })
.BuilderType(); // 此时在内存中生成了一个 Type
db.CodeFirst.InitTables(dynamicType); // 物理表同步生成
2. 强大的数据库维护 (DbMaintenance)
SqlSugar 封装了 DbMaintenance 接口,将各数据库底层复杂的系统表查询抽象为简单的 API,非常适合做数据库管理工具或自动化迁移。
- 元数据检索:
db.DbMaintenance.GetTableInfoList()获取所有表结构。 - 结构变更:
db.DbMaintenance.AddColumn("TableName", new DbColumnInfo(){...})动态加字段。 - 安全运维:
db.DbMaintenance.BackupDataBase("dbName", "path")快速备份。
3. 多租户与跨库联表查询
在大型系统中,数据往往散落在不同的服务器或数据库实例中。SqlSugar 提供了“天生”的跨库支持。
3.1 自动路由跨库 (TenantAttribute)
通过 ConfigId 标识不同的数据库,并利用特性绑定实体与库的关系。
// 库A的配置 ID 为 "Sales"
[Tenant("Sales")]
public class Order { ... }
// 库B的配置 ID 为 "Finance"
[Tenant("Finance")]
public class Invoice { ... }
// 执行时,SqlSugar 会自动切换连接
var list = db.Queryable<Order>()
.LeftJoin<Invoice>((o, i) => o.Id == i.OrderId)
.ToList();
3.2 灵活的手动联表
如果库名是动态的(如按年分库),可以使用 .As() 语法:
var query = db.Queryable<Order>().As("Database_2023.dbo.Orders")
.LeftJoin<Customer>((o, c) => o.CustomerId == c.Id, "Database_Shared.dbo.Customers")
.ToList();
4. 数据安全隔离:全局过滤器 (QueryFilter)
在多租户系统或逻辑删除需求中,手动在每个 Where 里写 IsDeleted == false 既低效又易出错。
// 配置全局过滤器
db.QueryFilter.AddTableFilter<IDeletedFilter>(it => it.IsDeleted == false);
// 此时所有的查询(包括联表查询)都会自动带上 IsDeleted = 0 的条件
var data = db.Queryable<UserEntity>().ToList();
5. 动态 CRUD 操作实战
对于动态创建的类,由于没有泛型类型,我们使用 ByObject 系列方法:
// 1. 根据动态类型创建对象
var obj = db.DynamicBuilder().CreateObjectByType(dynamicType, new Dictionary<string, object>() {
{ "ExtData", "这是一条动态插入的数据" }
});
// 2. 插入数据
db.InsertableByObject(obj).ExecuteCommand();
// 3. 动态查询
var list = db.Queryable(dynamicType).Where("Id = @id", new { id = 1 }).ToList();
结论
SqlSugar 不仅仅是一个 ORM,它更像是一个数据库操作框架。通过 CodeFirst 解决了结构一致性问题,通过 DynamicBuilder 解决了灵活性问题,而 多租户与过滤器 则解决了复杂的架构维护问题。
在当今微服务和低代码风靡的背景下,掌握这些动态操作技巧,能让你的系统架构具备极高的弹性。