EFCore动态切换Schema

最近作个分库分表项目,用到schema的切换感受仍是有些坑的,在此分享下。数据库

 

先简要说下咱们的分库分表缓存

分库分表规则

我定的规则是,订单号(数字)除以16,得出的结果为这个订单所在的数据库,而后他的余数表明他所在这个库里面的哪一个表。ui

而后在一个库里面有16个表,这个怎么实现呢?比较龊的办法是 Order1/Order2这样,不事后来我想了下,数据库默认(咱们是Sql Server)是有schema的(默认是dbo的那个东西),设计

而后我就打起这个东西的主意,后续跟dba确认方案可行后,就决定好比在同一个库里,第一套订单表是 p0.Order,第二套订单表就是p1.Order(有效取值 p0~p15)。blog

 

代码设计

若是说每次操做订单,你都要记得要先根据订单号拆分规则,找到这是哪一个数据库,再去找这是哪一个schema,我以为这代码也别写了,放弃把,这是不可维护的代码,不具有可持续发展性。接口

咱们必需要将一个分库分表这么一件事,抽象为某个单一的逻辑。文档

因而乎,DbContext是个好东西!字符串

当咱们在说Ef的时候,实际上咱们在讨论的主要就是他里面的DbContext。而一个DbContext,则逻辑上表明了一个数据库映射(包含数据库链接/表等和数据库相关的全部配置的集合)。get

只要咱们将分库分表这件事,抽象为如何获取一个DbContext,以后在对这个DbContext作你想作的操做,那么一切事情就简单多了!it

 

因而乎我设计了这么一个接口:

image

你给我一个订单号,我还你一个DbContext~

 

正题

如何让DbContext支持分库分表

这里主要有2个问题,一个是如何改链接字符串,另外一个如何改schema。

问题1简单,建立DbContext的时候原本就是要串链接字符串进去的,直接这里构造好链接字符串便可。

问题2比较复杂,也是这篇文章主要内容,首先个人设计是在建立DbContext,传入schema,在OnModelCreating里用这个schema初始化。

代码是这样子的:

image

因而乎你第一次建立DbContext的时候,schema是什么(别在乎我代码变量名当时写错了这么个细节),就永远是什么,后续你重复建立其余DbContext的时候其实这句话并不能让你修改schema。

 

后面我发觉,EfCore在指定表名的时候,是能够顺带指定schema的,因而乎在改下,改为了相似这样:

image

然而实践证实依然并无什么卵用。

 

坑了2次后我严重怀疑efcore里必定有某种级别的缓存机制,使得初次赋值以后某些信息不会再被更新(甚至于怀疑到efcore2.x引入的DbContextPool,然而我都是new出来的我没pool啊)。

 

后面一通乱找后不记得再哪一个网址(可是记得必定是stackoverflow里)找到了对这个类 IModelCacheKeyFactory的一些描述。

好像是efcore会对Model(你的实体)和DbContext之间产生一个缓存,而个人分库分表用的DbContext只有一个(只是动态修改了某些参数配置),因而乎以为应该就是这个东西缓存了的关系致使,而后我重写了这货的实现:

image

本质就是将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

相关文章
相关标签/搜索