高效批次刪除、更新資料的Zack.EFCore.Batch釋出三個新特性

Zack。EFCore。Batch是一個支援在EF Core中高效刪除和更新資料的開源庫。我們知道,EF Core中不支援高效的刪除和更新資料,所有的更新和操作都是逐條資料處理。比如,如果使用如下的語句刪除實現“刪除所有價格大於10元的書“:

ctx。RemoveRange(ctx。Books。Where(b => b。Price > 33))

那麼,EF Core會先執行Select * from books where price>33,然後再對於每一條資料執行delete from books where id=@id進行刪除。EF Core中批次資料的更新原理也是類似。因此在EF Core中進行大量資料的批次刪除、更新效率是比較低的。

為了能夠實現 “一句SQL實現資料的刪除、更新“,我開發了開源專案Zack。EFCore。Batch,這個開源專案實現瞭如下批次刪除的寫法:

await ctx。DeleteRangeAsync(b => b。Price > n || b。AuthorName == “zack yang”);

上面的C#程式碼就會執行如下的SQL語句,從而實現“一句SQL刪除資料“的效果:

Delete FROM [T_Books] WHERE ([Price] > @__p_0) OR ([AuthorName] = @__s_1)

這個開源專案使用EF Core實現SQL語句的翻譯,因此只要EF Core支援的資料庫,對應的Linq操作都可以實現翻譯成對應的方言SQL,比如下面的批次更新操作的Linq程式碼:

await ctx。BatchUpdate()    。Set(b => b。Price, b => b。Price + 3)    。Set(b => b。Title, b => s)    。Set(b => b。AuthorName,b=>b。Title。Substring(3,2)+b。AuthorName。ToUpper())    。Set(b => b。PubTime, b => DateTime。Now)    。Where(b => b。Id > n || b。AuthorName。StartsWith(“Zack”))。ExecuteAsync();

在SQL Server資料庫下就會翻譯成一條Update語句,如下:

Update [T_Books] SET [Price] = [Price] + 3。0E0, [Title] = @__s_1, [AuthorName] = COALESCE(SUBSTRING([Title], 3 + 1, 2), N‘’) + COALESCE(UPPER([AuthorName]), N‘’), [PubTime] = GETDATE()WHERE ([Id] > @__p_0) OR ([AuthorName] IS NOT NULL AND ([AuthorName] LIKE N‘Zack%’))

經歷使用者幾個月的使用和反饋issue,目前專案已經升級到1。4。3版,支援SQLServer、MySQL、PostgreSQL、Oracle、SQLite資料庫。理論上來講,只要EF Core支援的資料庫,Zack。EFCore。Batch都可以支援。如果您有其他資料庫需要支援,請和我聯絡。

除了已有的特性之外,Zack。EFCore。Batch新版增加了如下特性。

特性一、基於實體關係的資料過濾

在過濾條件中支援實體之間的關係。例如:

ctx。 DeleteRangeAsync

(a=>a。Comments。Any(c=>c。Message。Contains(“History”))||a。Author。BirthDay。Year<2000);

特性二、支援資料的批次插入

可以用如下的方式進行高效的批次插入:

List books = new List();for (int i = 0; i < 100; i++){       books。Add(new Book { AuthorName = “abc” + i, Price = new Random()。NextDouble(), PubTime = DateTime。Now, Title = Guid。NewGuid()。ToString() });}using (TestDbContext ctx = new TestDbContext()){       ctx。BulkInsert(books);}

BulkInsert()底層使用各個資料庫的BulkCopy機制實現資料插入,因此插入效率非常高。目前有如下兩個缺點:不支援關聯資料的自動插入,對於關聯的物件,請同樣呼叫BulkInsert()進行插入;由於PostgreSQL的。NET Core Provider還沒有支援BulkCopy,所以目前Zack。EFCore。Batch暫不支援PostgreSQL,我後面再去想辦法解決。

特徵三、支援Take()、Skip()來限制刪除和更新資料的範圍

批次刪除和批次更新都支援透過Take()、Skip()來實現部分刪除和部分更新,例子程式碼如下:

await ctx。Comments。Where(c => c。Article。Id == id)。Skip(3)。DeleteRangeAsync(ctx);await ctx。Comments。Where(c => c。Article。Id == id)。Skip(3)。Take(10)。DeleteRangeAsync(ctx);await ctx。Comments。Where(c => c。Article。Id == id)。Take(10)。DeleteRangeAsync(ctx); await ctx。BatchUpdate()。Set(c => c。Message, c => c。Message + “abc”)       。Where(c => c。Article。Id == id)       。Skip(3)       。ExecuteAsync(); await ctx。BatchUpdate()。Set(c => c。Message, c => c。Message + “abc”)       。Where(c => c。Article。Id == id)       。Skip(3)       。Take(10)       。ExecuteAsync();await ctx。BatchUpdate()。Set(c => c。Message, c => c。Message + “abc”)   。Where(c => c。Article。Id == id)   。Take(10)   。ExecuteAsync();

具體用法請訪問開源專案地址:https://github。com/yangzhongke/Zack。EFCore。Batch

NuGet地址:https://www。nuget。org/packages/Zack。EFCore。Batch/