EFCore.BulkExtensions是一個常用的EF core 批次處理資料的庫.
但是支援的資料庫相對較少.特別是.NET5.0版本 連MySQL都無法支援
這個庫就是改造的最新EFCore.BulkExtensions的程式碼
讓它能在.NET5.0中支援Mysql和達夢資料庫
由於5.0在升到最新9.0的過程中有比較重大的改變,所以.NET8+的 我還在弄..估計後面支援吧
使用方法如下:
using (TestDbContext ctx = new TestDbContext()) { List<Book> books2 = TestBulkInsert1.BuildBooks(); ctx.BulkInsert(books2); //批次插入 var book3 = ctx.Books.Take(1000).ToList(); ctx.BulkDelete(book3); //按實體批次刪除 ctx.Books.Where(a => a.BookType == BookType.Fictional).BatchDelete(); //按條件刪除 ctx.Books.Where(a => a.BookType == BookType.Scientific).BatchUpdate(a => new Book { Price = a.Price + 50, AuthorName = "gzy666" }); //批次按條件更新 var list = ctx.Books.Take(5000).ToList(); list.ForEach(a => a.AuthorName = "gzy8998"); ctx.BulkUpdate(list); //按實體批次更新 }
比較實用的是批次按實體進行修改、批次按實體刪除、批次插入
7.0+雖然支援了按條件進行修改和刪除但是批次處理 還是並未支援.
主要講解一下兩個資料庫的實現原理吧
1.MySql的實現方式
1.1批次插入
這其實就不用介紹了,就是最常見的SqlBulkCopy的形式進行資料匯入
優點就是量大管飽,速度快
缺點就是已經脫離了執行SQL的範疇,所以在實體監聽這些處理會比較麻煩
注意:Mysql使用SqlBulkCopy需要開啟local_infile功能,並需要在連線字串中配置:AllowLoadLocalInfile=true;
1.2批次修改
採用了Mysql的 on duplicate key update 語法進行批次處理
首先會建立臨時表,然後透過SqlBulkCopy將資料批次匯入至臨時表中
然後透過 解析實體產生 on duplicate key update 語法
類似如下SQL:
INSERT INTO my_table (column1, column2) SELECT column1 FROM TempTableName AS EXCLUDED
ON DUPLICATE KEY UPDATE <column1> = <value1>, <column2> = <value2>;
它會透過主鍵來判斷資料是否更新,然後從臨時表中將資料更新過去
最後會刪除臨時表,(mysql也可以配置為會話臨時表,這樣就不用手動刪除,會話結束了 會自動刪除)
1.3批次刪除
採用了 DELETE INNER JOIN 語法進行批次處理
同樣也是將資料匯入至臨時表中,但是這裡做了一些最佳化,只匯入主鍵ID,因為刪除只需要主鍵即可
最後會生成類似SQL:
DELETE A
FROM {tableInfo.FullTableName} AS A
INNER JOIN {tableInfo.FullTempTableName} B on A.{firstPrimaryKey} = B.{firstPrimaryKey};
這樣就可以快速的進行批次刪除.
2.達夢資料庫的實現方式
2.1批次插入
其實國產的達夢資料庫也提供了對應的SqlBulkCopy類,DmBulkCopy,我們直接按規範實現即可
(注意:達夢資料庫的DmBulkCopy,暫時只提供了同步的方法,所以並不支援async非同步處理)
2.2批次修改
批次修改的語法達夢就與Mysql差異較大了,但是也提供了對應的SQL
達夢採用 MERGE INTO的語法 可以從臨時表中將資料批次更新至源表
2.3批次刪除
批次刪除也和Mysql大同小異
最後會生成類似如下SQL:
DELETE FROM
{tableInfo.FullTableName} AS A
WHERE A.{firstPrimaryKey} IN
(SELECT B.{firstPrimaryKey} FROM {tableInfo.FullTempTableName} AS B )
從臨時表中根據主鍵刪除源表的資料.