EFCore动态切换Schema
最近做个分库分表项目,用到schema的切换感觉还是有些坑的,在此分享下。
先简要说下我们的分库分表
分库分表规则
我定的规则是,订单号(数字)除以16,得出的结果为这个订单所在的数据库,然后他的余数代表他所在这个库里面的哪个表。
然后在一个库里面有16个表,这个怎么实现呢?比较龊的办法是 Order1/Order2这样,不过后来我想了下,数据库默认(我们是Sql Server)是有schema的(默认是dbo的那个东西),
然后我就打起这个东西的主意,后续跟dba确认方案可行后,就决定比如在同一个库里,第一套订单表是 p0.Order,第二套订单表就是p1.Order(有效取值 p0~p15)。
代码设计
如果说每次操作订单,你都要记得要先根据订单号拆分规则,找到这是哪个数据库,再去找这是哪个schema,我觉得这代码也别写了,放弃把,这是不可维护的代码,不具备可持续发展性。
我们必须要将一个分库分表这么一件事,抽象为某个单一的逻辑。
于是乎,DbContext是个好东西!
当我们在说Ef的时候,实际上我们在讨论的主要就是他里面的DbContext。而一个DbContext,则逻辑上代表了一个数据库映射(包含数据库连接/表等和数据库相关的所有配置的集合)。
只要我们将分库分表这件事,抽象为如何获取一个DbContext,之后在对这个DbContext做你想做的操作,那么一切事情就简单多了!
于是乎我设计了这么一个接口:
你给我一个订单号,我还你一个DbContext~
正题
如何让DbContext支持分库分表
这里主要有2个问题,一个是如何改连接字符串,另一个如何改schema。
问题1简单,创建DbContext的时候本来就是要串连接字符串进去的,直接这里构造好连接字符串即可。
问题2比较复杂,也是这篇文章主要内容,首先我的设计是在创建DbContext,传入schema,在OnModelCreating里用这个schema初始化。
代码是这样子的:
于是乎你第一次创建DbContext的时候,schema是什么(别在意我代码变量名当时写错了这么个细节),就永远是什么,后续你重复创建其他DbContext的时候其实这句话并不能让你修改schema。
后面我发觉,EfCore在指定表名的时候,是可以顺带指定schema的,于是乎在改下,改成了类似这样:
然而实践证明依然并没有什么卵用。
坑了2次后我严重怀疑efcore里一定有某种级别的缓存机制,使得初次赋值之后某些信息不会再被更新(甚至于怀疑到efcore2.x引入的DbContextPool,然而我都是new出来的我没pool啊)。
后面一通乱找后不记得再哪个网址(但是记得一定是stackoverflow里)找到了对这个类 IModelCacheKeyFactory的一些描述。
好像是efcore会对Model(你的实体)和DbContext之间产生一个缓存,而我的分库分表用的DbContext只有一个(只是动态修改了某些参数配置),于是乎觉得应该就是这个东西缓存了的关系导致,然后我重写了这货的实现:
本质就是将DbContext里的当前的Schema暴露出给ModelCacheKey读取,然后进行Equal比较的时候Schema也作为一个Equal的因素,当两者比较不等的时候,就不会再采用之前错误Schema的缓存了
最后在创建DbContextOptionBuilder的时候Replace一下
builder.ReplaceService<IModelCacheKeyFactory, SchemaModelCacheFactory>();
即可完成
后续亲测都能动态切换schema,圆满完成。
后面发现(评论里提到的)其实这里已经有说明这个问题了,文档看不仔细,躺坑两行泪
https://docs.microsoft.com/zh-cn/ef/core/modeling/dynamic-model
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?