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中
喜歡延遲加載的人說,延遲加載很容易使用,在讀取屬性時不需要應用程式資料庫上下文. 延遲加載的缺點是對延遲加載的資料進行更多的資料庫通路. 讓查詢變慢, 本章描述的三種方法在我看來完全可以消除延遲加載的存在意義,它們可以帶來性能更高的資料庫通路