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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...