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
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...