歡迎光臨
每天分享高質量文章

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();

即可完成

後續親測都能動態切換schema,圓滿完成。

原文地址:https://www.cnblogs.com/leolaw/p/10461156.html


.NET社區新聞,深度好文,歡迎訪問公眾號文章彙總 http://www.csharpkit.com