跳转到主要内容
杨月昌的软件博客
返回

深度实践:使用 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,非常适合做数据库管理工具自动化迁移


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

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



上一篇
在 Blazor 应用中实现国际化与多语言支持:告别繁琐的 Resx
下一篇
跨年烟花:用 HTML5 Canvas 绘制指尖上的绚烂庆祝