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
EFCore动态切换Schema的更多相关文章
- Spring3 整合Hibernate3.5 动态切换SessionFactory (切换数据库方言)
一.缘由 上一篇文章Spring3.3 整合 Hibernate3.MyBatis3.2 配置多数据源/动态切换数据源 方法介绍到了怎么样在Sping.MyBatis.Hibernate整合的应用中动 ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法
一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...
- Spring多数据源的动态切换
Spring多数据源的动态切换 目前很多项目中只能配置单个数据源,那么如果有多个数据源肿么办?Spring提供了一个抽象类AbstractRoutingDataSource,为我们很方便的解决了这个问 ...
- Spring动态切换多数据源解决方案
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性.而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时 ...
- 【原】通过AOP实现MyBatis多数据源的动态切换
[环境参数]1.开发框架:Spring + SpringMVC + MyBatis 2.数据库A的URL:jdbc.url=jdbc:mysql://172.16.17.164:3306/ test? ...
- 170615、spring不同数据库数据源动态切换
spring mvc+mybatis+多数据源切换 选取Oracle,MySQL作为例子切换数据源.mysql为默认数据源,在测试的action中,进行mysql和oracle的动态切换. 1.web ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法
一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...
- springmvc+mybatis多数据源配置,AOP注解动态切换数据源
springmvc与springboot没多大区别,springboot一个jar包配置几乎包含了所有springmvc,也不需要繁琐的xml配置,springmvc需要配置多种jar包,需要繁琐的x ...
- AOP获取方法注解实现动态切换数据源
AOP获取方法注解实现动态切换数据源(以下方式尚未经过测试,仅提供思路) ------ 自定义一个用于切换数据源的注解: package com.xxx.annotation; import org. ...
随机推荐
- EF Linq中的左连接Left Join查询
linq中的join是inner join内连接,就是当两个表中有一个表对应的数据没有的时候那个关联就不成立. 比如表A B的数据如下 from a in A join b in B on a.BId ...
- 0510JS运算符
|-运算符|--基础运算符 + - * / %|----加号:数字的求和.字符串的拼接|----减号:数字的减法.对数字取反|----乘法.除法.取余 var a = 10; var b = 10; ...
- 卸载重装Mysql
卸载重装前请备份数据库 卸载 sudo apt autoremove --purge mysql-server-core-5.7 清理残留 sudo rm -r /var/lib/mysql* sud ...
- ubuntu 命令整合1
一.linux命令基本格式 命令名[选项] [参数] 注意: 命令名区分字母大小写 命令名必须有 选项.参数可以没有,选项一般使用减号开头二.具体Linux命令 1.who 显示登录系统中的用户的信息 ...
- 微信对账单处理-PHP
最近要做支付对账,即检查第三方支付与数据库中账单是否一一对应,涉及到微信对账单的处理,成功时,微信账单接口返回数据以文本表格的方式返回,第一行为表头,后面各行为对应的字段内容,字段内容跟查询订单或退款 ...
- springboot+mybatis+ehcache实现缓存数据
一.springboot缓存简介 在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),Spring Boot根据下面的顺序去侦测缓 ...
- SSM-SpringMVC-14:SpringMVC中大话注解式开发基础--呕心沥血版
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 注解的基础我不再多啰嗦,百度一搜很多,很详细啊,我就讲一下SpringMVC中的注解入门 通过注解的方式定义 ...
- SDKManager连不上墙外的网,列表刷新不出来怎么办?
现在我们都无法正常访问外国的网站了,尤其是Google,这个也没了,问题出不去,好多东西都解决的不是很好,包括SDKManager这个都无法刷新列表,当然在这里,我没有介绍你使用VPN的使用,这样做就 ...
- jQuery.on() 函数详解 【转载】
注意事项 1:on()为指定元素的一个或多个事件绑定事件处理函数.(可传递参数) 2:从jQuery 1.7开始,on()函数提供了绑定事件处理程序所需的所有功能,用于统一取代以前的bind(). d ...
- 在腾讯云(windows)上搭建node.js服务器
1:安装Node.js 使用MSI文件,并按照提示安装node.js,默认情况下,安装程序将 Node.js 发行到 C:\Program Files\nodejs. 但这里我们需要修改安装路径到:D ...