EF6學習筆記九:初識延遲加載、飢餓加載、顯式加載


要專業系統地學習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;
View Code

我自定義了一個打印方法,可以說是沒什么意義

db.Database.Log = MyConsole;
public static void MyConsole(string str)
        {
            Console.WriteLine($"四海的跟蹤:{str}");
        }
View Code

然后我對數據集查詢

using (EFDbContext db = new EFDbContext())
            {
db.Database.Log = MyConsole;
                var res = db.Orders.FirstOrDefault();
}
View Code

然后我們看看打印了什么東西

延遲加載(Lazy Loading)

現在我們就來看延遲加載

我有兩個model,Order訂單類和Product產品類,一對多,一個訂單包含多產品

現在延遲加載是顯式開啟的

public class EFDbContext:DbContext
    {
        public EFDbContext()
        {
            //  延遲加載  true:開啟,false:關閉
            Configuration.LazyLoadingEnabled = true;
            //Configuration.AutoDetectChangesEnabled = false;
        }
}
View Code

然后查詢訂單集合中的第一個訂單

var res = db.Orders.FirstOrDefault();
View Code

 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]
View Code

可以看到EF僅對Oders表進行了查詢,沒有查詢該訂單包含的產品

好,我現在要使用訂單中的產品數據了,於是,我查詢該訂單的第一條產品

var pro = res.Products.FirstOrDefault();
View Code

生成的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
View Code

這就是延遲查詢了,當我用的時候才執行查詢

 飢餓加載(Eager Loading)

你不使用延遲加載那就使用飢餓加載,顯示加載也是屬於延遲加載,我一次性拿到所有的數據。飢餓查詢使用Include()方法

現在我們查詢訂單集合中的第一個訂單,並且要求包含的產品集合都給我

db.Orders.Include("Products").FirstOrDefault();
View Code

生成的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
View Code

然后我們把這段SQL拿到數據執行看一下

 

 顯式加載(Explicitly Loading)

 顯式加載,如果關閉了延遲查詢,還可以用顯式加載來延遲加載實體。那為什么要弄這么個東西出來呢。可能就是因為延遲加載的問題,使用不當會造成性能問題,具體的性能問題,我現在還沒有太多認識。

我們先來看看,關閉延遲加載后,然后用延遲加載的方式來查詢會是什么結果。

設置Configuration.LazyLoadingEnabled = false;

查詢訂單集合的第一個訂單,查詢該訂單的第一個產品

var res = db.Orders.FirstOrDefault();
                var pro = res.Products.FirstOrDefault();
View Code

查詢訂單有SQL語句,當查詢產品就報錯了,因為產品是null

行,來顯式加載

通過DbEntityEntry<T>.Reference("").Load();加載實體

通過DbEntityEntry<T>.Collection("").Load();加載集合

var res = db.Orders.FirstOrDefault();
                db.Entry(res).Collection(x =>x.Products).Load();
View Code

 

 第一句只會對Order查詢,第二句查詢訂單中的產品,這樣就行了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM