最新文章 (全部类别)
CSFramework.EF分库分表解决方案
AI 使用笔记
线联ERP成本核算逻辑
线联ERP - 用户操作手册 - 成本核算
线联ERP - 用户操作手册 - 审计日志
线联ERP委外加工在途逻辑
SystemSettings 全局参数类使用
C/S Winform框架开发指南 - 如何新增系统消息参数(sys_SystemSettings表)
自动部署SSL证书 Certify The Web / Certify SSL/TLS Certificate Management
IIS 服务器错误 Server Error Code:500
.NET8 .NETCore运行环境下载
线联ERP - 生产模块主界面
线联ERP - 销售模块主界面
线联ERP - 人力资源模块主界面
线联ERP - 系统模块主界面
线联ERP - 财务模块主界面
线联ERP - 库存模块主界面
LinERP - 线联ERP主界面(HOME)
DevExpress的MemoEdit组件 Padding 不生效解决方案
线联ERP术语与缩略语
发布IIS .NET8 ASP.NET Core 应用站点踩坑
在线工具|好用的在线免费工具
线联ERP - 采购模块主界面
_Test测试(Admin)
线联ERP - 电子线材线束行业ERP系统主数据(基础资料)介绍
线联ERP - 基础资料模块主界面
线联ERP - 用户操作手册 - 附件管理
线联ERP - 用户操作手册 - 图片管理
线联ERP - 用户操作手册 - 单位换算
线联ERP软件与硬件对接列表
线联ERP软件安装环境
阿里企业邮箱配置SMTP 三方客户端安全密码
线联ERP - 用户操作手册 - 存货期初
LinERP - 线联ERP用户操作手册 - 系统登陆
线联ERP - 用户操作手册 - 查看在线用户
线联ERP - 用户操作手册 - 数据备份
线联ERP - 用户操作手册 - 工厂管理
线联ERP - 用户操作手册 - 帐套管理
线联ERP - 用户操作手册 - 语种设置
线联ERP - 用户操作手册 - 国际化多语言
线联ERP - 用户操作手册 - 报表管理
线联ERP - 用户操作手册 - 字段名管理
线联ERP - 用户操作手册 - 模块管理
线联ERP - 用户操作手册 - 广播消息
线联ERP - 用户操作手册 - 公司资料设置
线联ERP - 用户操作手册 - 系统参数设置
线联ERP - 用户操作手册 - 单据类型
线联ERP - 用户操作手册 - 号码规则
线联ERP - 用户操作手册 - 功能菜单
线联ERP - 用户操作手册 -分配临时角色
.net敏捷开发,创造卓越

CSFramework.EF分库分表解决方案


CSFramework.EF分库分表解决方案

 

本文基于 CSFramework.EF(C/S 框架网 V6.1 旗舰版 .NET8 数据访问层,EF Core 8)源码逐文件分析,回答三个问题:框架现在能不能分库、分表;分库分表时数据库名与表名该怎么命名;历史数据归档场景下,跨区间查询还能不能查得出来。文中所有结论均标注源码位置,便于复核。

一句话结论:“分库”框架层早已支持(消费方已实装账套机制);“分 Schema”是框架原生能力;“分表”目前只有预留字段、尚未接线,需要补齐四处改造。

一、结论速览

能力现状由谁决定改造量
分库(多数据库实例)已支持连接串 + 消费方账套表0(核心库无需改动)
分 Schema(同库多模式)已支持(框架原生)DatabaseConfig.Schema0
分表(同库多表名)未实现(TableSuffix 空壳)—中等:核心库 4 处 + 5 个提供程序收口
跨库事务有 API,但非 2PCDistributedTransaction强一致需另做

二、事实基线:三个分片维度

框架的分片入口只有一个:DatabaseConfig。它身上挂着三个维度——ConnectionString(库)、Schema(模式)、TableSuffix(表后缀)。三者的接线程度完全不同。

2.1 一个 IDatabase 实例 = 一个库

DatabaseFactory.GetDatabase(config) 每次调用产出一个独立实例,连接串直接决定打到哪个库。值得注意的是 IDatabase.DatabaseName 只是一个只读回读属性:取当前连接的 Database,取不到就退回 Schema(GenericDatabase.cs:61-73)。也就是说:框架既不生成库名,也不校验库名,库名完全由外部连接串决定。

2.2 Schema:唯一真正落地的分片维度

这是框架已经做实的分库分表能力,由三件东西配合完成:

  • GenericDbContext.ConfigSchema:调用 modelBuilder.HasDefaultSchema(config.Schema)(GenericDbContext.cs:104-107);
  • DatabaseEngine.RemoveEntitySchema(默认 true,DatabaseEngine.cs:202):自动剥掉实体 [Table] 上写死的 Schema,所以实体模型不需要指定 Schema;
  • SchemaModelCacheFactory 替换 EF 的 IModelCacheKeyFactory,把 Schema 并入模型缓存键(SchemaModelCache.cs:35-55)。

第三点是关键:OnModelCreating 只会执行一次,EF 对模型做了缓存。正是缓存键里加了 Schema,同一实体在不同 Schema 下才会有各自独立的模型,“动态 DbContext”才成立。

2.3 TableSuffix:预留字段,尚未接线

DatabaseConfig.TableSuffix(DatabaseConfig.cs:101-104)的注释原话是“表名后缀(分表时需要)”。但全仓库检索它的出现位置只有两处:定义处,以及消费方赋值处——而且赋的是空串(WebApi 端 DatabaseBuilder.cs:125:TableSuffix = "")。

没有任何一行代码读取它、更没有用它拼表名。作者留好了接口位,但分表功能从未接线。

2.4 表名唯一来源:[Table] 特性

ReflectionHelper.GetTableName(Type) 优先取 [Table].Name,无特性时回退类名(Helper/ReflectionHelper.cs:30-39)。实体注册时只做 modelBuilder.Entity(T),不指定表名(GenericDbContext.cs:85-89),整个解决方案内 ToTable( / SetTableName( 零命中。读路径拼 SQL 用的也是这个口径:GetDataByKey、SelectAll、RemoveAll<T>、IsExistsKeyValue<T>。

结论:今天的表名是编译期写死的,运行期没有任何一处会改写它。顺带一提,模型缓存键目前只含 Schema、不含表名,这一点在后面做分表时会变成最大的隐形地雷。

三、分库:框架已支持,消费方已实装

核心库视角很简单——每次 GetDatabase 就是一个新库实例,库名无约束、无校验。真正的分库规则,在消费方的账套机制里。

3.1 账套加载链路

环节说明
加载系统库按配置创建系统库实例并缓存
读取账套清单从系统库 tb_DataSet(IsUse="Y")读取,密码字段加密存储,读取时解密
组装连接串按本地(局域网 IP/端口)或远程(公网 IP/端口)二选一,调用 BuildConnectionString 生成
取库GetDatabase(DBID) 按账套编号取实例,GetDatabaseByDbName(DBName) 按库名取
动态加库AddDatabase(DBID, type, connStr, schema),WebApi 模式下动态注册

3.2 账套定义表 tb_DataSet 的关键字段

DataSetID(账套编号,唯一)、DBName(物理库名)、DatabaseType、Schema、LocalServerIP/Port、RemoteServerIP/Port、DBUserName、DBUserPassword(加密存储)、IsUse、IsVisible。

现行命名习惯:系统库 CSFrameworkV6_System(账套 ID 固定 SystemDB),默认业务库 CSFrameworkV6_Normal(账套 ID Normal);表按前缀分三类:dt_* 基础资料、sys_* 系统表、tb_* 业务表。

3.3 WebApi 侧:一个接口 = 一个库

WebApi 开发框架的做法是用派生接口区分库:UseDatabase<TDatabase>(...) 以接口全名作为配置项名称注册,需要几个库就定义几个 IDatabase 派生接口(如系统库访问器、业务库访问器)。

四、分表:需要补齐的四个改造点

要让 TableSuffix 真正生效,需要改四处。前两处必须同时做,拆开做必踩坑。

① 给 DbContext 增加表名配置

// GenericDbContext.OnModelCreating 内,ConfigSchema 之后追加一步
protected virtual void ConfigTableName(ModelBuilder modelBuilder)
{
    var suffix = _databaseConfig.TableSuffix;   // 如 "_202601"
    if (String.IsNullOrEmpty(suffix)) return;

    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        // 基表名来自 [Table] 特性或类名
        entityType.SetTableName(entityType.GetTableName() + suffix);
    }
}

② 模型缓存键必须并入 TableSuffix

// SchemaModelCache:缓存键只比 Schema,不比表名 —— 分表后必须一起改
readonly string _tableSuffix;   // 取自 DatabaseConfig.TableSuffix

protected override bool Equals(ModelCacheKey other)
{
    return base.Equals(other)
        && (other as SchemaModelCache)?._schema == _schema
        && (other as SchemaModelCache)?._tableSuffix == _tableSuffix;
}

public override int GetHashCode()
{
    var hashCode = base.GetHashCode() * 168;
    if (_schema != null) hashCode ^= _schema.GetHashCode();
    if (_tableSuffix != null) hashCode ^= _tableSuffix.GetHashCode();
    return hashCode;
}

不改这里的后果:EF 会认为“模型没变”而复用第一个分片的模型,后续所有分片都指向同一批物理表——数据静默写进第一张表,而且不报错。

③ 读路径统一加后缀

框架的写操作走 EF,但读操作(GetDataTable / ExecuteScalar / GetDataSet / ExecuteSql(Type) 等)多是自建 ADO.NET 连接拼 SQL。所以除了 EF 模型,还要把这些拼表名的地方统一收口成一个方法(例如 GetPhysicalTableName(Type)),至少覆盖:GetDataByKey、SelectAll、RemoveAll<T>、IsExistsKeyValue<T>。

只改 EF、不改读路径 = 写走分表、读走原表,读写打到不同的表且不报错。

④ 五个数据库提供程序各自的 override

SqlServer / MySql / Oracle / PostgreSql / 达梦五个提供程序里,凡是自己组装 SQL 或指定批量导入目标表名的 override(如 Oracle 的 SelectAll、RemoveAll、BulkInsert)都要一并加后缀。顺带修一个现存问题:Oracle 的 SelectAll 仍在用类名而非 [Table] 名,遇到类名与表名不一致的实体(例如 sys_Data_SN 类对应 sys_DataSN 表)会直接报表不存在。

五、命名规则

5.1 数据库名(分库)

  • 建议格式:CSFrameworkV6_{DataSetID},如 CSFrameworkV6_Normal、CSFrameworkV6_FactoryA;
  • 系统库固定为 CSFrameworkV6_System(多处常量引用,不要改);
  • 字符集只用 [A-Za-z0-9_],不要中文、空格、连字符——它会进入连接串、Oracle/达梦的 Schema、备份脚本的文件名;
  • 账套编号 DataSetID 是逻辑键(登录界面选择、实例缓存 key),可与库名保持一致便于排错。

5.2 表名(分表后缀)

  • 格式:{基表名}{分隔符}{后缀},框架侧只有“追加后缀”一种形态,没有前缀、没有替换;
  • 时间分片:tb_PO_202601(按月)、tb_PO_2026(按年);哈希分片:tb_PO_03(取模,定宽两位);
  • 后缀字符集同样只用 [A-Za-z0-9_],不要裸数字开头,不要含 -;
  • Schema 与表名之间的点号由 FormatSchema 自动补,后缀里不要带点。

5.3 各库标识符硬约束(决定上限)

数据库长度上限大小写备注
SqlServer128不敏感(取决于排序规则)格式化为 [表名]
MySql64取决于操作系统(Linux 下敏感)反引号包裹
PostgreSql63(超出静默截断)未加引号一律折叠成小写sys_DataSN 实际是 sys_datasn
Oracle12.2 前为 30,之后 128未加引号折叠成大写加了双引号就大小写敏感,必须与建表写法完全一致
达梦128同 Oracle 风格以 Schema(模式)连接

要五库通吃,按 30 个字符以内设计最保险。例如 tb_PO_202601 共 11 字符,安全;sys_Log_ApiVistior_202601 已 26 字符,接近上限。

六、历史数据归档实操

典型诉求:把几年前的旧数据搬出去做备份,归档表主要供查询。以采购订单 tb_PO(主表)/ tb_POs(明细)为例,把 2024/12/31 之前的数据分出去。

6.1 先看清实体,口径才不会错

 tb_PO(主表)tb_POs(明细)
主键isid(字符串 GUID32)isid(字符串 GUID32)
业务单号PONOPONO(关联键,未声明外键约束)
日期字段PODate(业务日期)、CreationDate只有 CreationDate,没有业务日期

迁移口径只能以主表 PODate 为准:明细表没有业务日期,自己筛不了,必须靠 PONO IN (...) 跟着主表走。另外 PODate 可空,空值单据不会被归档;补录单据(PODate 早、创建时间晚)会被一并搬走——这两点要先定死口径。

6.2 归档数据放哪里

方案做法框架改造量适用场景
A. 独立归档库(推荐)新建归档库,表名保持不变(仍是 tb_PO/tb_POs)0,AddDatabase(DBID, 类型, 连接串, Schema) 即可访问归档即备份,可整库脱机、设只读账号
B. 同库分表建 tb_PO_2024 / tb_POs_2024需完成第四节的 ①②改造必须留在同一个库

“归档 + 只读”这类诉求下方案 A 明显更划算:表名不变,就不用碰 TableSuffix、不用碰模型缓存键,现有 IDatabase 直接就能读。

6.3 搬迁步骤(幂等、可重跑)

  1. 建归档表——注意 SELECT INTO / CTAS 不会带主键和索引,事后必须单独创建;
  2. 抽主表:WHERE PODate < '2025-01-01'(即 2024/12/31 及之前);
  3. 抽明细:WHERE PONO IN (SELECT PONO FROM 归档主表);
  4. 对账:行数 + 金额合计双查,主表明细各一次,不一致就停下;
  5. 删原表:先明细、后主表,按 PONO 分批(每批 1000~5000 行),不要一次性 DELETE(会锁表、日志暴涨);
  6. 备份归档库,可设为只读账号或只读文件组。

 

不要用 DistributedTransaction 去包“插入 + 删除”:它的提交是对各库逐个 Commit,不是两阶段提交,第二个库失败时第一个库已提交、回滚不了。顺序必须定死为先插 → 对账 → 后删,每一步幂等,失败可重跑。

  •  
版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
C/S框架网
上一篇:SystemSettings 全局参数类使用
下一篇:没有了
评论列表

发表评论

评论内容
昵称:
关联文章

EFCore+Scheme(数据库架构)实现分库分表支持多种主流数据库解决方案
.Net 下高性能分表分库组件 (类似ShardingSphere原理)
CSFramework.WebApiV3.分库分表
CSFramework.WebApiV3.CSFramework.EF 组件使用
C/S框架-WebService架构下分页查询数据解决方案
OracleException:“ORA-00942: 表或视图不存在”解决方案
CSFramework.WebApiV3.VS解决方案
CSFramework开发框架采用一个数据库解决方案(合并数据库)
CSFramework软件版本自动升级程序 - VS解决方案
CSFramework.Workflow - 可视化工作流引擎 - 业务系统集成解决方案
CSFramework.EF 数据库框架 - 支持达梦数据库
CSFramework开发框架3.0解决方案改名教程
表格内显示多表关联数据解决方案(Join,View,Lookup)
代码生成器加载用户表和视图报错解决方案|C/S框架网
CSFramework旗舰版快速开发框架目录结构以及解决方案介绍
CSFramework.EF数据库初始化
CSFramework.Workflow - 可视化工作流引擎 - VS解决方案
CSFramework.ClientFoundation与ClientDemo两个解决方案区别与用途
C#源代码安全缺陷与提高源代码质量解决方案
VS解决方案专业改名工具 CSFramework.Rename V1.0 - C#版

热门标签
软件著作权登记证书 .NET .NET Reactor .NET5 .NET6 .NET7 .NET8 .NET9 .NETFramework AI编程 APP AspNetCore AuthV3 Auth-软件授权注册系统 Axios B/S B/S开发框架 B/S框架 BSFramework Bug Bug记录 C#加密解密 C#源码 C/S CHATGPT CMS系统 CodeGenerator CSFramework.DB CSFramework.EF CSFramework.License CSFrameworkV1学习版 CSFrameworkV2标准版 CSFrameworkV3高级版 CSFrameworkV4企业版 CSFrameworkV5旗舰版 CSFrameworkV6.0 CSFrameworkV6.1 CSFrameworkV6旗舰版 DAL数据访问层 DaMeng Database datalock DbFramework DeepSeek Demo教学 Demo实例 Demo下载 DevExpress教程 Docker Desktop DOM ECS服务器 EFCore EF框架 Element-UI EntityFramework ERP ES6 Excel FastReport GIT HR HR考勤系统 IDatabase IIS JavaScript LinERP LINQ MES MiniFramework MIS MSSQL MySql NavBarControl NETCore Node.JS NPM OMS Oracle资料 ORM PaaS POS PostgreSql Promise API PSD QMS RedGet Redis RSA SAP Schema SEO SEO文章 SQL SQLConnector SQLite SqlServer Swagger TMS系统 Token令牌 VS2022 VSCode VS升级 VUE WCF WebApi WebApi NETCore WebApi框架 WEB开发框架 Windows服务 Winform 开发框架 Winform 开发平台 WinFramework Workflow工作流 Workflow流程引擎 XtraReport 安装环境 版本区别 报表 备份还原 踩坑日记 操作手册 成本核算系统 达梦数据库 代码生成器 电子线材ERP 迭代开发记录 功能介绍 官方软件下载 国际化 海康威视考勤 基础资料窗体 架构设计 角色权限 开发sce 开发工具 开发技巧 开发教程 开发框架 开发平台 开发指南 客户案例 快速搭站系统 快速开发平台 框架升级 毛衫行业ERP 秘钥 密钥 企业网络维护 权限设计 软件报价 软件测试报告 软件加壳 软件简介 软件开发框架 软件开发平台 软件开发文档 软件授权 软件授权注册系统 软件体系架构 软件下载 软件著作权登记证书 软著证书 三层架构 设计模式 生成代码 实用小技巧 视频下载 收钱音箱 数据锁 数据同步 塑木地板行业ERP 推荐软件 微信小程序 未解决问题 文档下载 喜鹊ERP 喜鹊软件 系统对接 线联ERP 线束ERP 详细设计说明书 新功能 信创 行政区域数据库 需求分析 疑难杂症 蝇量级框架 蝇量框架 用户管理 用户开发手册 用户控件 在线软件 在线支付 纸箱ERP 智能语音收款机 自定义窗体 自定义组件 自动升级程序
联系我们
联系电话:13923396219(微信同号)
电子邮箱:23404761@qq.com
站长微信二维码
微信二维码