[翻譯 EF Core in Action 2.4] 載入相關資料
Entity Framework Core in Action
Entityframework Core in action是 Jon P smith
所著的關於Entityframework Core 書籍。原版地址. 是除了官方文件外另一個學習EF Core的不錯途徑, 書中由淺入深的講解的EF Core的相關知識。因為沒有中文版,所以本人對其進行翻譯。 預計每兩天一篇更新 PS: 翻譯難免限於本人水平有不準確的地方,建議英文水平不錯的同學直接檢視原版,有不足的地方歡迎指正
第一部分目錄導航
載入相關資料
之前我向你展示了Book實體類,它有其他三個實體的導航屬性: PriceOffer,Review和BookAuthor. 下面介紹如何使用程式碼訪問這些資料. 你有以下方式載入資料: 貪婪載入,顯式載入,選擇載入和懶載入(在EF Core 2.1中)
有一點很重要,EF Core預設不會載入實體類的任何關係(導航屬性),如果載入了Book類,在預設情況下Book實體的每個導航屬性都為null
預設不載入任何關係的行為是正確的,這意味著EF Core最小化了資料庫訪問. 如果你想載入一個關係則新增需要程式碼告訴EF Core. 下面介紹三種方法,以及它們的優缺點
貪婪載入: 載入與主實體類的關係
載入相關資料的第一種方法是貪婪載入. 貪婪載入需要告訴EF Core在載入主實體資料的查詢中載入導航屬性. 使用兩個方法Include和ThenInClude指定預先載入. 下個清單展示了Book實體類例項查詢Books表的第一行資料以及貪婪載入單個關係Reviews
- EF6 EF Core的貪婪載入與EF 6.x的方法類似, 但EF Core改進了語法和SQL實現. EF 6.x沒有ThenInclude方法, 並且EF 6.x的sql實現是嘗試在一個查詢中載入所有資料和集合,這樣的SQL查詢很可能是低效的. EF Core在一個單獨的查詢中載入集合,你可以在前面的SQL部分看到這一點
下面我們看一個更復雜的例子,下面的清單展示了查詢第一本書並且貪婪載入它所有的關係.
之前展示了使用貪婪載入方法Include獲取AuthorsLink關係(一級關係),直接由載入的實體類引用的關係. Include後面使用ThenInclude載入二級關係,本例中是BookAuthor的Author表. 這種方式(Include後面使用ThenInclude)是訪問深層次關係的標準方法,你可以使用更多的ThenInclude深入更深的關係
如果資料不存在,比如Book類的Promotion屬性指向的可選PriceOffer類,Include不會失敗,它只是載入不到任何東西,如果是集合會返回一個空集合. ThenInclude也是這樣. 如果前面的Include或Theninclude為空,後面的ThenInclude會被忽略
貪婪載入的缺點是會載入所有的資料,有時你不需要某些部分資料,例如圖書列表不需要書籍描述,而圖書描述一般會很長.
注: 在EF Core2.0中,如果你在查詢中使用了不必要的Include方法,則會有一個警告,比如 context.Books.Include(b => b.Promotion).Where( b => b.Promotion.NewPrice > 10).Select(b => b.BookId)
程式碼中使用了include,但它是不必要的,因為查詢只返回了BookId. EF Core團隊為此情況添加了警告,因為沒有必要使用Inlcude方法.
顯式載入: 在載入了實體類之後載入關係
第二個方法是顯式載入,載入了主實體類之後,使用顯式載入其他所需的關係. 下面的程式碼首先載入了書籍,然後使用顯式載入命令讀取所有關係
顯式載入有一個額外的命令,在載入資料的同時並且可用查詢. 下面的程式碼展示了使用顯式載入方法Query命令查詢評論數量並載入每個評論的所有星級評分. 你可以在Query方法後使用LINQ命令,例如Where,Orderby等
顯式載入的優點是不會立即載入實體的關係. 這對於在某些情況下需要相關資料,顯式載入會很有用. 你還會發現在複雜業務邏輯中顯式載入也很有用
顯式載入的缺點是會產生更多的資料庫往返,這可能是低效的. 如果你事先知道所需的資料,那麼貪婪載入通常會更好,因為載入關係所需的資料庫往返次數更少
選擇載入: 載入實體類的特定屬性和關係
第三種方法是使用LINQ的Select方法明確的選擇需要的資料,我稱之為選擇載入. 下面展示了使用Select方法從Book類中選擇屬性,在查詢中執行特定的程式碼獲取書的評論數量
Select查詢方法的優點是隻載入你需要的資料,在你不需要所有的資料時,這會很有用. 上面的查詢程式碼只需要一個Select SQL命令獲取所有資料. 在資料庫往返次數方面也很少. EF Core將查詢的p.Reviews.Count
轉換為SQL命令,在資料庫中完成計數. 如下面的SQL所示
SELECT TOP(1) [p].[Title], [p].[Price], (
SELECT COUNT(*)
FROM [Review] AS [r0]
WHERE [p].[BookId] = [r0].[BookId] )
FROM [Books] AS [p]
選擇載入的缺點是需要為每個屬性/計算編寫程式碼. 這會很繁瑣, 在10.3節中我介紹了一種自動化的方法
注: 在本章的後面,你會看到更復雜的選擇載入案例,我們會使用這種型別的載入構建圖書應用程式的圖書列表查詢
EF Core 2.1中的延遲載入
在EF 6.x中將屬性標記為virtual,在讀取到該屬性時會進行資料庫訪問. 延遲載入新增到了EF Core 2.1中
喜歡延遲載入的人說,延遲載入很容易使用,在讀取屬性時不需要應用程式資料庫上下文. 延遲載入的缺點是對延遲載入的資料進行更多的資料庫訪問. 讓查詢變慢, 本章描述的三種方法在我看來完全可以消除延遲載入的存在意義,它們可以帶來效能更高的資料庫訪