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

相關文章
相關標籤/搜索