要專業系統地學習EF前往《你必須掌握的Entity Framework 6.x與Core 2.0》這本書的作者(汪鵬,Jeffcky)的博客:https://www.cnblogs.com/CreateMyself/
EF數據加載三種方式:延遲加載、飢餓加載、顯示加載
每種加載方式都有其應用場景,應用不當會導致性能問題
我剛剛有點整懵了,目前算是有點明白,現在只是初步了解一下,把我剛剛搞的東西整理一下
延遲加載(Lazy Loading) 和淘寶的商品列表一樣,下拉刷新,按需加載
飢餓加載 (Eager Loading) 加載父對象時同時加載子對象
顯式加載 (Explicitly Loading)當我們禁用了延遲加載,仍然可以通過顯式加載來延遲加載相關實體
EF中默認是開啟延遲加載,那么我們怎么知道自己的查詢是延遲加載呢?辦法就是查詢EF生成的SQL語句,他什么時候生成SQL語句,在什么時候執行查詢。
要追蹤SQL命令的執行,在SQL server數據庫管理工具里面-->工具-->SQL Server Porfiler,這東西不錯
我們也可以用一個更簡單的方式,EF上下文有個Database.Log Action<string>類型的屬性
如果是控制台項目,那么可以講Console.WriteLine賦值給他,然后當有SQL執行,會為我們打印一些信息
db.Database.Log = Console.WriteLine;
我自定義了一個打印方法,可以說是沒什么意義
db.Database.Log = MyConsole; public static void MyConsole(string str) { Console.WriteLine($"四海的跟蹤:{str}"); }
然后我對數據集查詢
using (EFDbContext db = new EFDbContext()) { db.Database.Log = MyConsole; var res = db.Orders.FirstOrDefault(); }
然后我們看看打印了什么東西

延遲加載(Lazy Loading)
現在我們就來看延遲加載
我有兩個model,Order訂單類和Product產品類,一對多,一個訂單包含多產品
現在延遲加載是顯式開啟的
public class EFDbContext:DbContext { public EFDbContext() { // 延遲加載 true:開啟,false:關閉 Configuration.LazyLoadingEnabled = true; //Configuration.AutoDetectChangesEnabled = false; } }
然后查詢訂單集合中的第一個訂單
var res = db.Orders.FirstOrDefault();
EF生成並執行了一條SQL語句
SELECT TOP (1) [c].[Id] AS [Id], [c].[OrderNO] AS [OrderNO], [c].[Description] AS [Description], [c].[AddTime] AS [AddTime] FROM [dbo].[tb_Orders] AS [c]
可以看到EF僅對Oders表進行了查詢,沒有查詢該訂單包含的產品
好,我現在要使用訂單中的產品數據了,於是,我查詢該訂單的第一條產品
var pro = res.Products.FirstOrDefault();
生成的SQL語句如下
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Price] AS [Price],
[Extent1].[Unit] AS [Unit],
[Extent1].[FK_Order_Id] AS [FK_Order_Id],
[Extent1].[AddTime] AS [AddTime]
FROM [dbo].[tb_Products] AS [Extent1]
WHERE [Extent1].[FK_Order_Id] = @EntityKeyValue1
這就是延遲查詢了,當我用的時候才執行查詢
飢餓加載(Eager Loading)
你不使用延遲加載那就使用飢餓加載,顯示加載也是屬於延遲加載,我一次性拿到所有的數據。飢餓查詢使用Include()方法
現在我們查詢訂單集合中的第一個訂單,並且要求包含的產品集合都給我
db.Orders.Include("Products").FirstOrDefault();
生成的SQL語句如下,很多
:SELECT [Project2].[C1] AS [C1], [Project2].[Id] AS [Id], [Project2].[OrderNO] AS [OrderNO], [Project2].[Description] AS [Description], [Project2].[AddTime] AS [AddTime], [Project2].[C2] AS [C2], [Project2].[Id1] AS [Id1], [Project2].[Name] AS [Name], [Project2].[Price] AS [Price], [Project2].[Unit] AS [Unit], [Project2].[FK_Order_Id] AS [FK_Order_Id], [Project2].[AddTime1] AS [AddTime1] FROM ( SELECT [Limit1].[Id] AS [Id], [Limit1].[OrderNO] AS [OrderNO], [Limit1].[Description] AS [Description], [Limit1].[AddTime] AS [AddTime], [Limit1].[C1] AS [C1], [Extent2].[Id] AS [Id1], [Extent2].[Name] AS [Name], [Extent2].[Price] AS [Price], [Extent2].[Unit] AS [Unit], [Extent2].[FK_Order_Id] AS [FK_Order_Id], [Extent2].[AddTime] AS [AddTime1], CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2] FROM (SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[OrderNO] AS [OrderNO], [Extent1].[Description] AS [Description], [Extent1].[AddTime] AS [AddTime], 1 AS [C1] FROM [dbo].[tb_Orders] AS [Extent1] ) AS [Limit1] LEFT OUTER JOIN [dbo].[tb_Products] AS [Extent2] ON [Limit1].[Id] = [Extent2].[FK_Order_Id] ) AS [Project2] ORDER BY [Project2].[Id] ASC, [Project2].[C2] ASC
然后我們把這段SQL拿到數據執行看一下

顯式加載(Explicitly Loading)
顯式加載,如果關閉了延遲查詢,還可以用顯式加載來延遲加載實體。那為什么要弄這么個東西出來呢。可能就是因為延遲加載的問題,使用不當會造成性能問題,具體的性能問題,我現在還沒有太多認識。
我們先來看看,關閉延遲加載后,然后用延遲加載的方式來查詢會是什么結果。
設置Configuration.LazyLoadingEnabled = false;
查詢訂單集合的第一個訂單,查詢該訂單的第一個產品
var res = db.Orders.FirstOrDefault(); var pro = res.Products.FirstOrDefault();
查詢訂單有SQL語句,當查詢產品就報錯了,因為產品是null

行,來顯式加載
通過DbEntityEntry<T>.Reference("").Load();加載實體
通過DbEntityEntry<T>.Collection("").Load();加載集合
var res = db.Orders.FirstOrDefault(); db.Entry(res).Collection(x =>x.Products).Load();
第一句只會對Order查詢,第二句查詢訂單中的產品,這樣就行了
