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
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...