当前位置: 首页 > news >正文

多租户下的系统业务开发过程探讨

设计数据库

万层高楼从底起,开发应用项目,数据库的设计很重要,它可能是业务对象,业务流程的综合设计,好的数据库设计可以减少后期的重复返工,提高开发效率。
表名前缀区分,一般表名称,根据不同的业务关系,我们可以使用不同的前缀进行区分,使用前缀,可以非常方便区分不同的业务表,如我们可以一般基础表使用 “TB_” 定义前缀,基础设施的系统表使用"SYS_"定义前缀等。
按照业务区分比较可以在很多表的时候,让我们快速查找到对应的表名。

数据库的模型设计,我们建议在第三方的数据库设计工具上进行设计,如PowerDesigner这样的设计工具,使用工具设计数据库有很多好处,一个是可以高效率进行调整,二是根据需要生成不同的数据库类型Sql语句,三是可以全局了解各个表之间的关系等等。
使用PowerDesigner这样的数据库设计工具,能够在很大程度上提高我们数据库的设计效率。

多租户系统设计原则:
只要是业务表,一律带 tenant_id 字段,并且查询时需要根据租户过滤。
什么时候可以不加 tenant_id? 只有一种情况:全局表,这种是 平台共享数据,不属于某个租户吗,如:租户表,字典表、参数表、系统配置表、菜单表等。

系统推荐ID方案:
大多数 ERP 系统推荐:

主键ID:BIGINT 业务编码:VARCHAR

主键ID使用分布式ID:

Snowflake Leaf Sonyflake

生成 64bit BIGINT:

178923741239123

特点:

  • 全局唯一
  • 有时间顺序
  • 仍然是 BIGINT

因此使用BIGINT + Snowflake 方案。

结构:

id BIGINT PRIMARY KEY

生成:

  • Snowflake ID

有了这些基础的规则,我们就可以开始使用PowerDesigner建模工具设计数据库了,如下所示。


根据我们前面介绍的基础表设计,整理了相关的设计模型,如下所示。

ERP仓库管理的业务表比较多,先做好基础内容,后续再继续分析介绍。

这次我设计的数据库是基于MySQL来设计的,方便以后迁移到Python+FastAPI+SqlAlchemy上更方便。

由于PowerDesigner可以生成相关的表SQL,我们一次性设计好后,导出相关的SQL表,为后续创建表准备。

然后在数据库管理工具 Navicat Premium 17(或更高版本均可)上进行数据库表的生成和管理即可。

前期我们现在粗略准备好相关的表,后续可以对表增加更多的约束,如唯一性,索引等要求,进一步提高安全性和性能即可。

2、项目框架的生成

设计好数据库后,我们通过代码生成工具进行整个项目框架的生成,这样对于我们在开发新项目上有很好的好处,里面的项目层级、类之间的引用关系,已经处理好了,这样对我们处理起来就非常方便。

要了解项目的快速生成,需要从官网下载《代码生成工具Database2Sharp》工具后进行使用,该工具支持多种框架的项目开发,我们这里以《SqlSugar开发框架》的项目生成为例介绍。

《SqlSugar开发框架》项目框架后端为.netcore的WebAPI服务端,同时可以支持多终端的项目框架,我们先利用工具来生成后端所需要的基础和BS管理前端,后续需要再进行扩展即可,基于Web API可以对接多个终端。

我们利用代码生成工具来进行后端代码的生成,代码生成工具支持把表和字段的备注信息生成到类和属性的注释代码,表和字段小写自动转换为对应的Pascal命名模式。

选择所有的表生成:

设置代码生成的表过滤前缀名称和项目主命名空间:

最终生成的项目文件如下所示,包括接口层、实体模型层、服务层。

其中的基类通过泛型的方式,封装抽象了大多数常规的增删改查接口,在代码生成工具的智能处理下,会结合数据库的字段和备注信息,生成相关的函数内容,我们生成后进行一定的微调即可。

位置:Core/Interface/IOperationLogService.cs

namespace WHC.SugarProject { /// <summary> /// 操作日志表,应用层服务接口定义 /// </summary> public interface IOperationLogService : IMyCrudService<OperationLogInfo, long, OperationLogPagedDto>, ITransientDependency { } }

位置:Core/Modal/OperationLogInfo.cs

namespace WHC.SugarProject { /// <summary> /// 操作日志表 /// </summary> [SugarTable("sys_operation_log")] public class OperationLogInfo : Entity<long> { /// <summary> /// 默认构造函数(需要初始化属性的在此处理) /// </summary> public OperationLogInfo() { this.Id = Yitter.IdGenerator.YitIdHelper.NextId(); //雪花ID生成 this.CreatedAt = DateTime.Now; } #region Property Members /// <summary> /// 主键ID /// </summary> [SugarColumn(IsPrimaryKey = true)] public override long Id { get; set; } /// <summary> /// 租户ID /// </summary> //[Required] [SqlSugar.SugarColumn(ColumnName = "tenant_id")] public virtual long? TenantId { get; set; } /// <summary> /// 用户ID /// </summary> //[Required] [SqlSugar.SugarColumn(ColumnName = "user_id")] public virtual long? UserId { get; set; } = 0; /// <summary> /// 操作用户名 /// </summary> //[Required] public virtual string Username { get; set; } ....

位置:Core/Service/OperationLogService.cs

namespace WHC.SugarProject { /// <summary> /// 操作日志表 应用层服务接口实现,。 /// 注意:由于MyCrudService需要引用IOperationLogService来记录操作日志,因此这里本尊的基类只能是BaseCrudService,否则会导致循环引用。 /// </summary> public class OperationLogService : BaseCrudService<OperationLogInfo,long, OperationLogPagedDto>, IOperationLogService { /// <summary> /// 构造函数 /// </summary> public OperationLogService(IApiUserSession currentApiUser) { this.CurrentApiUser = currentApiUser; } ......

而一般Service层,我们生成代码的时候,会提供几个重写的函数处理,默认增加了一些对应的内容,如下所示。

在我们提供的Service层的重写函数中,对于基础条件过滤是一个很重要的规则重写,如对于多租户来说,我们请求的数据仅限于当前租户的数据范围,因此需要进行数据范围的过滤,如下函数所示。

/// <summary> /// 子类重写最高一级的Query封装,增加一些共性的过滤,如is_deleted, tenent_id的处理。 /// </summary> /// <returns></returns> protected override ISugarQueryable<UserInfo> BaseCreateFilteredQuery() { var query = base.BaseCreateFilteredQuery(); query = query.Where(t => t.IsDeleted == 0); //不需要删除记录 if (!isPlatformAdmin) { query = query.Where(t => t.TenantId == CurrentApiUser.TenantId);//非管理员需要带上租户ID,用来隔离数据 } return query; }

通过最顶级逻辑条件的过滤,任何数据请求都会以当前租户的范围进行条件过滤了。

而基类封装常规CRUD接口,如下所示。

有了基础Core核心模块的支持,我们就可以再WebAPI项目中整合相关的接口在控制器层了,在SqlSugar框架的代码生成的时候也有对应WebAPI的控制器类的生成,我们整合到项目后,如下所示。

测试项目的Swagger启动后的接口文档展示,如下所示。

http://www.cnnetsun.cn/news/1577122.html

相关文章:

  • 好写作AI:降重服务在高校毕业论文指导中的角色异化与反思
  • **基于Python的物理模拟系统设计与实现:从理论到代码落地**在现代计算机图形学、游戏开发和工程
  • 2026本地教培GEO实操:大模型软文框架设计与留资防坑指南
  • Ollama GUI架构解析:现代本地LLM交互界面的技术实现与隐私优先设计
  • 光刻机背后的数学魔术:拆解Abbe和Hopkins模型如何预测芯片上的图形
  • CBOX央视影音
  • 图像比对与像素级分析:用diffimg实现高效差异检测
  • 如何快速上手PySceneDetect:视频场景分割的终极指南 [特殊字符]
  • 告别手动重标:基于Python脚本的Labelme数据集增强与JSON同步更新实战
  • CSCAN磁盘调度算法实战:从真题解析到避坑指南
  • 导师认可的AI写作辅助软件星级排名(2026 权威发布)
  • 告别Vetur!Vue 3项目从VSCode插件、TS配置到Vite构建的完整避坑指南
  • 告别OOM崩溃!Python 3.9+智能体内存调度策略全解,含一键安装脚本与内存占用下降67%实测数据
  • VITA57.1标准实战:手把手教你设计兼容FMC接口的FPGA载板
  • 从合并果子到修篱笆:用C++优先队列(priority_queue)搞定两道经典贪心题
  • 3步掌握B站视频下载:BilibiliDown跨平台解决方案完全指南
  • FLUX.1-dev-fp8-dit文生图开源大模型部署:支持LoRA微调的ComfyUI环境配置
  • 实测Nanbeige 4.1-3B Streamlit UI:二次元风格聊天机器人搭建
  • Boss-Key终极指南:如何用一键隐藏技术保护你的办公隐私
  • OpenCascade避坑指南:TopoDS_Shape共享机制与常见错误排查
  • Notepad4:高效编辑全能工具从入门到精通
  • ScanTailor Advanced:开源扫描文档处理的高效解决方案
  • 从Flamingo到FocusLLaVA:视觉token压缩如何从‘硬编码’走向‘自适应’?
  • 2024最新Bypass Paywalls Clean全流程使用指南:从原理到实战的浏览器扩展技术手册
  • 视频渲染引擎技术指南:HDR画质增强与开源实现方案
  • Stable Yogi Leather-Dress-Collection基础教程:SD1.5底座模型float16加载详解
  • ChanlunX缠论工具:重构技术分析的自动化引擎
  • BMS充电管理避坑指南:从国标原理到AutoSar SWC设计的5个关键点
  • Lite-Avatar模型压缩技术:从理论到实践
  • OpenClaw+Qwen3-VL:30B:多模态AI助手案例展示