969 字
5 分钟
深度实践:使用 SqlSugar 实现动态建模、多库维护与跨库管理

简介#

在构建 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 解决了灵活性问题,而 多租户与过滤器 则解决了复杂的架构维护问题。

在当今微服务和低代码风靡的背景下,掌握这些动态操作技巧,能让你的系统架构具备极高的弹性。

深度实践:使用 SqlSugar 实现动态建模、多库维护与跨库管理
https://sw.rscclub.website/posts/sqlsugar/
作者
杨月昌
发布于
2023-12-18
许可协议
CC BY-NC-SA 4.0