EFCore分表實現

来源:https://www.cnblogs.com/queque/archive/2022/09/26/16730570.html
-Advertisement-
Play Games

實現原理 當我們new一個上下文DbContext 後, 每次執行CURD方式時 ,都會依次調用OnConfiguring(),OnModelCreating()兩個方法。 OnConfiguring() 我們將用來替換一些服務實現,以支持分表的工作 OnModelCreating() 我們將用來重 ...


實現原理

當我們new一個上下文DbContext 後, 每次執行CURD方式時 ,都會依次調用OnConfiguring(),OnModelCreating()兩個方法。

  • OnConfiguring() 我們將用來替換一些服務實現,以支持分表的工作
  • OnModelCreating() 我們將用來重新實現 實體與資料庫表 的映射關係

每次調用OnModelCreating()時,會判斷實體與資料庫表的映射關係有沒有改變,如果改變則採用新的映射關係。

判斷是否發生改變,通過替換 IModelCacheKeyFactory 介面的實現來完成。詳情可見:在具有相同 DbContext 類型的多個模型之間進行交替

IModelCacheKeyFactory 實現

DbContextBase 是一個DbContext的實現,,ShardingRuleDbContextBase的一個共有屬性。
根據分表規則的不同,每次的映射關係也會不同。

 public class DynamicModelCacheKeyFactoryDesignTimeSupport : IModelCacheKeyFactory
 {
        public object Create(DbContext context, bool designTime)
            => context is DbContextBase dynamicContext
                ? (context.GetType(), dynamicContext.ShardingRule, designTime)
                : (object)context.GetType();

        public object Create(DbContext context)
            => Create(context, false);

 }

OnConfiguring() 替換介面實現

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
            base.OnConfiguring(optionsBuilder);
            //如果分頁規則有 ,代表需要分頁, 那麼需要替換對應的服務實現
            if (!string.IsNullOrEmpty(this.ShardingRule))
            {
                optionsBuilder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactoryDesignTimeSupport>(); 
            }
 }

ModelCustomizer 實現

在每次調用 OnModelCreating() 時,方法內部會調用實現IModelCustomizerModelCustomizer.csCustomize()方法,我們可以將映射關係寫在此方法內。

通過繼承實現:
IShardingTypeFinder 是一個類型查找器,請自行實現。

public class ShardingModelCustomizer : ModelCustomizer
{

        public ShardingModelCustomizer(ModelCustomizerDependencies dependencies) : base(dependencies)
        {
        }

        public override void Customize(ModelBuilder modelBuilder, DbContext context)
        {
            base.Customize(modelBuilder, context);
            var dbContextBase = context as DbContextBase;
            var shardingTypeFinder = dbContextBase.ServiceProvider.GetService<IShardingTypeFinder>();
            //查找需要重新映射表名的類
            var shardingTypes = shardingTypeFinder.FindAll(true);

            if (shardingTypes != null && shardingTypes.Count() > 0)
            {

                if (context is DbContextBase contextBase)
                {
                    if (!string.IsNullOrEmpty(contextBase.ShardingRule))
                    {
                        foreach (var type in shardingTypes)
                        {
                            switch (contextBase.DbContextOptions.DatabaseType)
                            {
                                case DatabaseType.SqlServer:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");
                                    break;
                                case DatabaseType.Sqlite:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");
                                    break;
                                case DatabaseType.MySql:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}".ToMySQLName());
                                    break;
                                case DatabaseType.Oracle:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}".ToOracleName());
                                    break;
                                default:
                                    modelBuilder.Entity(type).ToTable($"{type.Name}_{contextBase.ShardingRule}");
                                    break;
                            }
                        }
                    }
                }

            }



        }

}

OnConfiguring() 替換介面實現

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  {
            base.OnConfiguring(optionsBuilder);
            //如果分頁規則有 ,代表需要分頁, 那麼需要替換對應的服務實現
            if (!string.IsNullOrEmpty(this.ShardingRule))
            {
                optionsBuilder.ReplaceService<IModelCacheKeyFactory, DynamicModelCacheKeyFactoryDesignTimeSupport>().ReplaceService<IModelCustomizer, ShardingModelCustomizer>();
            }
  }

DbContextBase構造函數修改

上文提到了ShardingRule 這個屬性的出現 , 如何給這個屬性賦值呢?
有兩種方式:

  • 構造函數傳參
  • 通過介面獲取

構造函數傳參

 public string ShardingRule { get; set; }
 public DbContextBase(string shardingRule, DbContextOptions options) : base(options)
 {
            ShardingRule = shardingRule;
 }

通過介面獲取

IShardingRule是實現規則名稱的自定義介面,自行實現

 protected DbContextBase(DbContextOptions options, IServiceProvider serviceProvider)
          : base(options)
 {
            ShardingRule = (serviceProvider.GetService<IShardingRule>()).GetValue();
 }

使用方式

這裡只介紹構造函數傳參使用方式

 DbContextOptionsBuilder<DbContextBase> optionsBuilder = new DbContextOptionsBuilder<DbContextBase>();
 optionsBuilder.UseSqlServer("connStr");
 var options =  optionsBuilder.Options;
 using (var dbContext = new DbContextBase("202209", options))
 {
        //TODO....
             
 }

跨上下文使用事務

這裡需要註意的是,跨上下文使用事務必須使用同一個連接,所以optionsBuilder.UseSqlServer(connection);這裡的寫法改變一下,使用同一連接

            DbContextOptionsBuilder<DbContextBase> optionsBuilder = new DbContextOptionsBuilder<DbContextBase>();
            IDbConnection connection = new SqlConnection("connStr");
            optionsBuilder.UseSqlServer(connection);
            var options =  optionsBuilder.Options;
            using (var dbContext = new DbContextBase("202209", options))
            {
                using (var  transaction =await dbContext.Database.BeginTransactionAsync())
                {
                    using (var dbContext2 = new DbContextBase("202210", options))
                    {

                        await dbContext2.Database.UseTransactionAsync(transaction);
                        //TODO....
                        transaction.Commit();
                    }
                }
               
            }

總結

EFCore分表的實現大致全是這樣,沒有什麼區別。可以參考一些開源的框架,對現有的系統進行適當的調整,畢竟別人寫的並不一定適合你。希望這篇文章可以幫到你。

我自是年少,韶華傾負。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 順序存儲二叉樹的概念 從數據存儲來看,數組存儲方式和樹的存儲方式可以相互轉換,即數組可以轉換成樹,樹也可以轉換成數組, 看下麵的示意圖。 要求: 右圖的二叉樹的結點,要求以數組的方式來存放 arr : [1, 2, 3, 4, 5, 6, 6] 要求在遍曆數組 arr 時,仍然可以以前序遍歷,中序遍 ...
  • 函數 1.字元串函數 #(1)add() 對兩個數組的元素進行字元串連接 import numpy as np print(np.char.add(["xiaodu"],["good"])) print(np.char.add(["xiaodu","dudu"],["good","nice"])) ...
  • 事情是這樣的:今天晚上,女朋友讓我十二點催她睡覺。 不過,可是我實在太困了,熬不下去…… 是吧?女朋友哪有睡覺重要? 但,女朋友的命令,我是不敢違抗的…… 但是睡覺也不能缺! 這時候我們該怎麼辦呢?是時候讓Python登場了! Python登場這次我們來做一個自動發送微信的程式,在深夜十二點的時候給 ...
  • 1、初衷 開發中經常需要做一些介面的簽名生成和校驗工作,最開始的時候都是每個介面去按照約定單獨實現,久而久之就變的非常難維護,因此就琢磨怎麼能夠寫了一個比較通用的簽名生成工具。 2、思路 採用鏈式調用的方式,使得簽名的步驟可以動態拼湊組合。 3、直接看效果 //設置數據源 var signSourc ...
  • .Net7 的到來的同時,也帶來了 C# 11,而令我最期待的就是 C# 11 的 原始字元串了,當我知道這個的時候,簡直比過年還要開心。 非原始字元串 首先我們看看現在寫字元串的方式 var str = @" 雪莉:""有人在嗎?"" 神樂:""他們有事出去了,你有什麼困擾呢? 萬事屋神樂為您服務 ...
  • 1. 發佈打包前端管理平臺(ant-design-vue) 2. 發佈打包後端(.NET6-WebApi) .NET6 webAPI orm: free sql 資料庫:mysql5.7 3. 發佈打包H5端(uni) 播放器使用: import Player from 'xgplayer'; // ...
  • 相關下載: 資料庫的負載均衡-示例代碼(dp1-DbBalance.rar) 資料庫的負載均衡-示例代碼(dp1-DbBalance.rar) 支持.Net/.Net Core/.Net Framework 為了演示資料庫的負載均衡(Load Balance),我們先創建三個資料庫,它們的名字分別為 ...
  • 用戶可以在 Windows 10 和 Windows 11 電腦上使用 winget 命令行工具來發現、安裝、升級、刪除和配置應用程式。 此工具是 Windows 程式包管理器服務的客戶端介面。 以下是 Windows 包管理器上可用的 .NET 版本列表: .NET VersionSupport ...
一周排行
    -Advertisement-
    Play Games
  • MQTTnet 是一個高性能的MQTT類庫,支持.NET Core和.NET Framework。 MQTTnet 原理: MQTTnet 是一個用於.NET的高性能MQTT類庫,實現了MQTT協議的各個層級,包括連接、會話、發佈/訂閱、QoS(服務質量)等。其原理涉及以下關鍵概念: MqttCli ...
  • 在WPF中,源屬性(Source Property)指的是提供數據的屬性,通常是數據模型或者其他控制項的屬性,而目標屬性(Target Property)則是數據綁定的目標,通常是綁定到控制項的屬性,例如TextBlock的Text屬性。數據綁定將源屬性的值自動更新到目標屬性中。 主要包含以下幾個事件: ...
  • async/await 是 C# 中非同步編程的關鍵特性,它使得非同步代碼編寫更為簡單和直觀。下麵深入詳細描述了 async/await 的使用場景、優點以及一些高級使用方法,並提供了相應的實例源代碼。 使用場景: I/O 操作: 非同步編程特別適用於涉及 I/O 操作(如文件讀寫、網路請求等)的場景。在 ...
  • 使用過office的visio軟體畫圖的小伙伴都知道,畫圖軟體分為兩部分,左側圖形庫,存放各種圖標,右側是一個畫布,將左側圖形庫的圖標控制項拖拽到右側畫布,就會生成一個新的控制項,並且可以自由拖動。那如何在WPF程式中,實現類似的功能呢?今天就以一個簡單的小例子,簡述如何在WPF中實現控制項的拖拽和拖動,... ...
  • 1、Blazor Hybrid簡介 Blazor Hybrid 使開發人員能夠將桌面和移動本機客戶端框架與 .NET 和 Blazor 結合使用。在 Blazor Hybrid 應用中,Razor 組件在設備上是本機運行的。 這些組件通過本地互操作通道呈現到嵌入式 Web 視圖控制項。 組件不在瀏覽器 ...
  • 除了內置的數據集,scikit-learn還提供了隨機樣本的生成器。通過這些生成器函數,可以生成具有特定特性和分佈的隨機數據集,以幫助進行機器學習演算法的研究、測試和比較。 目前,scikit-learn庫(v1.3.0版)中有20個不同的生成樣本的函數。本篇重點介紹其中幾個具有代表性的函數。 1. ...
  • 從0到1,手把手帶你開發截圖工具ScreenCap------002實現通過文件對話框,選擇合適的文件夾,自定義預設的圖片保存位置,簡單易學 ...
  • 每次談到容器的時候,除了Docker之外,都會說起 Kubernetes,那麼什麼是 Kubernetes呢?今天就來一起學快速入門一下 Kubernetes 吧!希望本文對您有所幫助。 Kubernetes,一種用於管理和自動化雲中容器化工作負載的工具。 想象一下你有一個管弦樂隊,將每個音樂家視為 ...
  • 目錄 基本說明 安裝 Nginx 部署 VUE 前端 部署 Django 後端 Django admin 靜態文件(CSS,JS等)丟失的問題 總結 1. 基本說明 本文介紹了在 windows 伺服器下,通過 Nginx 部署 VUE + Django 前後端分離項目。本項目前端運行在 80 埠 ...
  • 從0到1,手把手帶你開發截圖工具ScreenCap------003實現最小化程式到托盤運行,- 為了方便截圖乾凈,實現最小化程式到托盤運行,簡潔,勿擾,實現最小化程式到托盤運行, 實現托盤菜單功能,實現回顯主窗體, 實現托盤開始截屏, 實現氣泡信息提示,實現托盤程式提示,實現托盤退出程式, 封裝完... ...