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做你想做的操作,那么一切事情就簡單多了!

 

於是乎我設計了這么一個接口:

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM