為了修複 Entify Framework Core 中許多已發現的缺陷,微軟在 EF Core 3 中引入了 40 個中斷性變更。我們可以在微軟檔案中檢視完整的中斷性變更串列,本文僅列舉幾個主要的點。
客戶端查詢
為了突破 EF Core SQL 生成器的限制,預設只在客戶端執行部分查詢。這意味著對於部分不能轉換成 SQL 的 LINQ 查詢,需要從資料庫載入資料表,併在記憶體中執行其餘的操作。在 2.1 版本之前,Group By 都是在客戶端執行的。
這種方式的缺點是,Where() 子句中的一個問題可能導致 EF Core 載入整張資料表。開發人員還發現,在無法生成相關子查詢的情況下,它將執行成百上千個二級查詢。
新的預設行為是 EF Core 僅允許在客戶端執行最終的 Select() 操作。如果 EF Core 不能生成正確的 SQL,將引發異常。開發人員可以改寫這個行為,但微軟更希望開發者遇到這個問題時先嘗試提交一個 bug 請求。
可以在“3.0 查詢指導原則大綱和決策點“中瞭解更多有關該變更的資訊。
引數化及插值 SQL
正如我們在 2017 年報告的那樣,EF Core 的字串插值特性引起了許多關註。使用該特性可以將內插字串自動轉換為引數化 SQL,但前提是這些字串之前沒有被儲存在臨時變數中。
v1 = context.Customers.FromSql($“SELECT * FROM Customers WHERE City = {city}”) |
var sql = $“SELECT * FROM Customers WHERE City = {city}” |
v2 = context.Customers.FromSql(sql) |
在上面的例子中,v1 是正確引數化的,而 v2 則引入了一個 SQL 註入漏洞。
為了消除上述漏洞,將移除 FromSql 函式,並使用 FromSqlRawand 和 FromSqlInterpolated 替代。
臨時鍵
EF Core 通常會建立臨時主鍵來跟蹤新物體。這些臨時主鍵以負數的形式儲存在鍵屬性中(例如 CustomerKey 或 OrderId)。理論上,這些臨時主鍵在生成時會被真正的鍵所替換,不過也存在幾個例外情況,比如那些在使用者介面上顯示的假鍵甚至會被儲存到資料庫中。
EF Core 3 將把此類跟蹤資訊轉移到物體的跟蹤資訊中,讓鍵屬性只持有資料。
級聯刪除時機
在呼叫諸如 context.Remove() 等方法時,級聯刪除將立即發生。在此之前,EF Core 在 SaveChanges 被呼叫之前不會計算哪些子項被刪除,因此很難預測到底會發生什麼。該變更主要影響那些用於記錄將要修改 / 刪除哪些資料項日誌的程式碼。
可以透過將 CascadeDeleteTiming 和 DeleteOrphansTiming 選項設定成 CascadeTiming.OnSaveChanges 來還原以前的行為。
查詢型別已過時
與之前版本的 Entity Framework 不同,EF Core 被設計成只能處理包含主鍵的資料表。這是有問題的,因為檢視或儲存過程的結果沒有主鍵。所以 EF core 2.1 引入了查詢型別的概念。
本質上,查詢型別使用的是並行物件模型。開發人員使用 DbQuery 而不是 DbSet 來定義它們,使用 ModelBuilder.Query<>() 而不是 ModelBuilder.Entity<>() 來註冊它們,並使用 DbContext.Query<>() 而不是 DbContext.Set<>() 來呼叫它們。
許多開發人員抱怨查詢型別和物體型別之間存在不必要的混淆,因此查詢型別被移除了。從 EF Core 3 開始,開發人員應該對所有資料源使用常規的 DbSet 模型。如果沒有主鍵,開發人員在註冊物體時只需使用 .HasNoKey() 來註解它們。
忽略屬性的 Getter 和 Setter
在過去,除非要物化查詢結果,否則 EF Core 將呼叫屬性的 getter 或 setter 方法。在進行查詢時,如果已知屬性的支援欄位,它將繞過屬性,直接寫入底層欄位。
在這個變更之後,如果已知屬性的支援欄位,將始終使用底層支援欄位。這樣做的好處是可以防止意外觸發業務邏輯。
缺點是諸如更新計算欄位之類的業務邏輯也不會被觸發。因此,我們可能需要修改 UsePropertyAccessMode 來獲得我們想要的行為。
支援字端檢測
在檢測支援欄位時,程式碼有時候會有歧義。在過去,EF Core 只能根據內部排名系統來猜測應該設定哪個欄位。
在 EF Core 3 中,任何有歧義的地方都將丟擲異常。不過,開發人員必須手動指出要使用模型生成器生成的哪個欄位。
用 ValueTask 替換 Task
將 Task 作為物件被認為是.NET 的最大錯誤之一。雖然對於長時間執行的任務來說是可以接受的,但當建立了大量的短期任務時,它常常會造成過大的記憶體壓力,所以新版本引入了基於結構的備選方案 ValueTask 。
為了支援這種新型別,更新了 FindAsync 和 NextValueAsync 等幾個方法,讓它們傳回 ValueTask 而不是 Task 。這不會影響那些等待獲取結果的程式碼,但如果要對任務執行其他操作,可能需要呼叫 AsTask() ,將其從 ValueTask 轉換到 Task 。
簡化 IEntityType 和 IProperty
刪除了這兩個介面中的五個屬性,並用擴充套件方法進行替換。這樣做的依據是如果介面錶面越小就容易實現。
朋友會在“發現-看一看”看到你“在看”的內容