推薦關注「碼俠江湖」加星標,時刻不忘江湖事
這是 EF Core 系列的第七篇文章,上一篇文章講述了 EF Core 中的實體數據修改。
這篇文章講一講 EF Core 如何進行批量操作。
在眾多的 ORM 框架中,EF Core 的功能并不是最強大的那個,性能可能也不是最好的那個。但卻一直是最穩定、最安全,擴展能力最強、使用人數最多的那個。
雖然在性能方面,在 EF Core 6.0 中已經得到了非常大的提升。
但是在功能方面, EF Core 一直有一個不完善的地方,就是它不能很好的支持數據的批量操作,也就是批量刪除和批量更新。
所以這篇文章就先從比較常用的批量刪除和批量更新講起。
點擊上方或后方藍字,閱讀 EF Core 系列合集。
批量操作
在 EF Core 中批量更新和刪除數據,都需要先進行查詢,把數據加載到內存中,然后再對數據操作,最后再SaveChanges
保存到數據庫。
我們來看這個示例:
var?accounts?=?_context.Accounts.Where(account?=>?account.Age?>=?1);foreach?(var?a?in?accounts)
{a.Age?=?a.Age?+?1;
}_context.SaveChanges();
為了更新 Accounts
中實體的 Age
屬性,我們必須查詢出所有符合條件的實體集合,然后用遍歷的方式,在內存中去逐個修改實體的 Age
屬性。
最后,通過 SaveChanges
方法保存修改。
運行程序,結果如下圖所示:

通過控制臺日志可以發現,前后總共執行了 3 條 SQL 語句,1 條 Selet 語句和 2 條 Uptete 語句。
第一條 Selet 語句,是為了查詢出所有符合條件的數據,由于數據庫中只有 2 條數據,所以后面 2 條 Uptete 語句,是針對這 2 條數據的更新操作。
如果我們把更新操作換成刪除操作,EF Core 也會如此去做。
大家可以想象一下,如果批量更新或者刪除的數據量比較大,那么這樣的操作,性能無疑是非常底下的。
因此,我們需要一種在 EF Core 中,只使用一條 SQL 語句,就可以批量刪除或更新數據的方法。
由于這個功能確實比較常用,很多其它第三方的 ORM 框架,幾乎也都支持這個操作。
但為什么作為 ORM 框架大佬的 EF Core,卻不提供這個功能呢?
簡單來說,EF Core 的開發團隊認為,這樣做會導致 EF Core 的對象狀態跟蹤混亂。
比如對于同一個上下文類,如果用批量刪除的方法刪除了數據,那么在被刪除之前,查詢出來的數據狀態就混亂了。
畢竟,EF Core 是一個成熟且安全性高的 ORM 框架,必然會考慮潛在風險的存在。
如果想要完美實現,可能需要重構 EF Core 的代碼,工作量方面會比較大。
但是,我們作為開發者,完全可以根據場景需求,來規避這些問題的存在。
比如在一個 Web 應用中,刪除操作通常都是在一個 HTTP 請求中完成的,不同的 HTTP 請求上下文是不同的,所以基本不會涉及到 EF Core 開發團隊擔心的問題。
即便在某些特殊場景下,涉及到在同一個上下文里,數據刪除之前就把數據查詢出來的場景,那也完全可以通過在刪除之后,再重新查詢一次的方式,來規避這個問題。
未來 EF Core 會不會添加這個功能,我們不得而知,但我們也有自己的解決方法。
第一個解決方法,就是執行原生 SQL 語句,不過它的缺點我們在前面的文章中已經提過,就不再多說。
第二個解決方法,是使用第三方的 ORM 框架,比如 FreeSQL、SugarSQL,它們都提供了批量更新和批量刪除的功能,使用起來也非常簡單。
不過,這種方法的缺點就是必須在項目替換掉 EF Core ,使用第三方的 ORM 框架。
目前 EF Core 是 .NET 中,使用率最高的 ORM 框架,主打安全性與穩定性,而且 6.0 版本性能也得到了大量的改善,所以不建議輕易更換。
第三個解決方法,就是使用 EF Core 的擴展插件,由于 EF Core 在全球范圍有著最多的用戶基數,所以也形成了一個強大的生態環境,擁有很多的第三方擴展。
這同樣也是第三方 ORM 框架,所無法比擬的地方。
我們可以在 EF Core 的官方文檔,查閱到被官方收集的第三方擴展插件和工具。
這里面支持批量操作的擴展插件有兩個:「EFCore.BulkExtensions」 和 「Entity Framework Plus」。
它們都支持最新的 EF Core,更新也比較穩定。
不同的是,E「FCore.BulkExtensions」 功能專一,僅擴展了批量操作方面的功能,同時也支持 「SqlBulkCopy」,也就是大數據量的批操作。
由于 「SqlBulkCopy」 只支持 SQLServer 和 SQLite ,所以 「EFCore.BulkExtensions」 只支持 SQLServer 和 SQLite。
「EF Plus」 功能更加強大,擴展了更多的查詢功能,它分為免費版和收費版,基礎的批量操作免費版就可以支持,高級批量操作以及 SqlBulkCopy 則只有收費版支持。
如果使用的是 MySQL,或者不需要 SqlBulkCopy,那么 「EF Plus 免費版」是首選,因為它支持更多的數據庫,擴展了更豐富的查詢功能。
安裝好 EF Plus,這里我將剛才批量更新的操作,改為 EF Plus 來實現:
<PackageReference?Include="Z.EntityFramework.Plus.EFCore"?Version="6.13.19"?/>
_context.Accounts.Where(account?=>?account.Age?>=?1).Update(account?=>?new?Account?{Age?=?account.Age?+?1},update?=>?update.Executing?=?command?=>?Console.WriteLine(command.CommandText));
Update
就是 EF Plus 擴展的方法,它的第一個參數是要更新的數據,第二個參數是一個執行攔截器委托,這里用來打印準備執行的 SQL 語句。
現在運行程序,可以在控制臺中看到:

執行的是 1 條 UPDATE 語句,這條 SQL 語句會更新所有 Accounts
中符合條件的 Age
字段。
除了批量更新,批量刪除也同樣簡單。
更多的示例,大家可以看 EF Plus 的官網文檔。
更多精彩內容,請關注我▼▼
如果喜歡我的文章,那么
在看和轉發是對我最大的支持!
(戳下面藍字閱讀)
ASP.NET 6 中間件系列
查缺補漏系統學習 EF Core 6? 系列
推薦關注微信公眾號:碼俠江湖
? ? ? ? ? ? ? ? ? ? ? ??覺得不錯,點個在看再走喲