解析ASP.NET Mvc開發之EF延遲加載


目錄:

1) 從明源動力到創新工場這一路走來

2)解析ASP.NET WebForm和Mvc開發的區別

3)解析ASP.NET Mvc開發之查詢數據實例

-------------------------------------------------------------------------------------------------------

哈哈,既然學習EF,怎么可能不涉及到EF的延遲加載特性呢!那么到底什么是EF的延遲加載呢?這篇文章我們就來看看。

EF延遲加載:就是使用Lamabda表達式或者Linq 從 EF實體對象中查詢數據時,EF並不是直接將數據查詢出來,而是在用到具體數據的時候才會加載到內存。

一,實體對象的Where方法返回一個什么對象?

大家來看一下上一篇文章的代碼來分析一下:

#region 查詢文章列表+ActionResult Article()
        /// <summary>
        /// 查詢文章列表 /// </summary>
        /// <returns></returns>
        public ActionResult Article() { //通過db對象獲取文章列表
            db.BlogArticles.Where(p => p.AIsDel == false);//使用Lamabda表達式來獲取為被刪除的文章 //使用Lamabda表達式來獲取數據 //返回一個List<T>的對象來存儲文章列表
            List < Models.BlogArticle > list= db.BlogArticles.Where(p => p.AIsDel == false).ToList(); //也可以使用Linq來獲取數據 
            List<Models.BlogArticle> list1 = (from p in db.BlogArticles where p.AIsDel == false select p).ToList(); //使用ViewData來傳遞list對象
            ViewData["DataList"] = list; return View(); } #endregion

 

為了體驗延遲加載,我們把代碼做修改如下:

#region 查詢文章列表+ActionResult Article()
        /// <summary>
        /// 查詢文章列表
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            //通過db對象獲取文章列表
            db.BlogArticles.Where(p => p.AIsDel == false);//使用Lamabda表達式來獲取為被刪除的文章

            DbQuery<Models.BlogArticle> query = (db.BlogArticles.Where(p => p.AIsDel == false)) as DbQuery<Models.BlogArticle>;

            List<Models.BlogArticle> list = query.ToList();
            //使用ViewData來傳遞list對象
            ViewData["DataList"] = query;

            return View();
        }
        #endregion

 

在這里我們為什么要使用DbQuery<T>來接收呢?

首先我們來看使用db.BlogArticles.Where()來獲取文章列表的時候,Where()方法給我們返回一個什么類型的對象呢?我們把鼠標放在Where()方法上后,會發現Where會返回給我們一個IQueryable的泛型接口對象,如下圖:

 

 

那我們是不是需要使用IQueryable對象來接收獲取的對象呢,代碼如下:

       //where()方法返回一個IQuery的接口
            IQueryable < Models.BlogArticle > query= db.BlogArticles.Where(p => p.AIsDel == false);

 

這里的Query到底能不能取到值呢?我們來運行調試程序,結果如下:

 

 

 

我們在局部變量窗口看到Query已經取到了值。但是根據面向對象的原則,接口是不能直接實例化的,但是這里的代碼又是不報錯的,那是為什么呢?

根據面向對象的里氏替換原則,我們都知道,這里實際上是返回了一個IQueryable對象的子類對象。

注意:C#里氏替換原則,子類對象可以賦值給父類對象。也就是說子類可以替換父類出現的地方。但是父類對象一定不可以替換子類對象。

 

也就是說Where()方法返回了一個IQueryable接口的子類對象,並且賦值給了它的父類對象IQueryable。

那么Where()到底返回了一個什么樣的對象呢(什么樣的IQueryable的子類對象呢)?

 再次看上面的局變量窗口中query的返回值類型為,如下圖:

 我們可以很明顯的看出,query的返回類型為DbQuery類型。

那我們就用DbQuery來接收對象,代碼如下:

DbQuery<Models.BlogArticle> query = (db.BlogArticles.Where(p => p.AIsDel == false)) as DbQuery<Models.BlogArticle>;

因為Where()方法返回的是IQueryable對象,所以要把對象轉換成DbQuery對象;

 

二,DbQuery<T>泛型接口類的延遲加載

上面的定義已經說過了EF延遲加載的定義,那么在這里我們在query查詢到對象時,數據庫有沒有執行查詢操作呢?

這里我們借助Sql Server的自身的Profiler軟件來查看,

①打開Sql Server Profiler 軟件,新建一個查詢,剛開始,是有查詢記錄的,如下圖:

 

 

②我們使用上圖中的,紅色箭頭指的橡皮,清除一下記錄,如下圖:

 

 

③我們再次啟動調試,運行代碼,當程序運行到斷點的時候,我們看到query還沒有值,如下圖:

 

 

④單步調試,進行下一步,我們在局部變量窗口中發現query已經取到了值,如下圖:

query的值,如下圖:

那么我們的Sql Server Profiler 跟蹤器發生了什么變化呢?沒有發生任何變化,如下圖:

 

 

我們如果使用ADO.NET操作數據庫,查詢完數據后,數據會立即送給接收的對象(比如:DataTable對象),但是EF操作數據庫怎么卻沒有立即去查詢數據呢?

⑤DbQuery對象的延遲加載

當我們使用query對象的時候才回去查詢數據庫,我們繼續執行下一步,結果如下:

 

這個時候list取到了值,然后Sql Server  Profiler 也發生了變化,有了查詢數據庫的記錄,如下圖:

 也就是說,當query對象ToList()的時候,才發生了查詢數據庫的操作。

三,總結:

1)EF中的DbQuery對象操作數據庫的時候發生延遲加載,而直接使用List<T>來接受對象時則不會;

2)延遲加載不會立即去查詢數據庫,而是在使用數據的時候才EF才會去查詢數據庫。

 

 


免責聲明!

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



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