19

我發現我很困惑延遲加載等EF:延遲加載,渴望裝載和「枚舉枚舉」

首先,是這兩個語句等效:

(1) Lazy loading: 
_flaggedDates = context.FlaggedDates.Include("scheduledSchools") 
.Include ("interviews").Include("partialDayAvailableBlocks") 
.Include("visit").Include("events"); 

(2) Eager loading: 
_flaggedDates = context.FlaggedDates; 

在其他詞,(1)「包含」會導致導航集合/屬性與請求的特定集合一起被加載,而不管您使用延遲加載的事實...對嗎?

而在(2)中,即使您沒有專門請求它們,該語句也會加載所有導航實體,因爲您正在使用熱切加載......對吧?

其次:即使您正在使用預先加載,數據實際上不會從數據庫下載到你「枚舉枚舉」,如下面的代碼:

var dates = from d in _flaggedDates 
      where d.dateID = 2 
      select d; 
foreach (FlaggedDate date in dates) 
{ 
... etc. 
} 

的數據實際上不會被下載(「枚舉」),直到foreach循環...對嗎?換句話說,「var dates」行定義了查詢,但查詢不會在foreach循環之前執行。由於(如果我的假設是正確的),急切加載和延遲加載之間的真正區別是什麼?????????????????????????????????????????????看來無論哪種情況,直到枚舉纔會顯示數據。我錯過了什麼嗎?

(我的具體的經驗是代碼優先,POCO發展,順便......雖然這些問題可以應用更普遍。)

+0

EntityFramework使用預先加載/延遲加載(加載數據的通用軟件術語)來提取相關對象和集合。被緩存的查詢執行是LINQ的一個工件,它允許查詢更加靈活(在某些情況下,它們可能不會被執行)。 – jwize 2014-11-18 07:26:18

回答

17

你的說明(1)是正確的,但它是一個例子Eager Loading而不是延遲加載。

您對(2)的描述不正確。 (2)技術上根本不使用加載,但如果嘗試訪問標記日期上的任何非標量值,將使用延遲加載。

無論哪種情況,只要您嘗試使用_flaggedDates「執行某些操作」,就會發現沒有數據會從數據存儲區加載。但是,發生的情況在每種情況下都不相同。 (1):急切的加載:只要你開始你的for循環,你指定的每一個對象都將從數據庫中被拉出來,並被構建成一個巨大的內存數據結構。這將是一項非常昂貴的操作,從數據庫中提取大量數據。但是,它將全部發生在一次數據庫往返中,並且執行單個SQL查詢。

(2):延遲加載:當for循環開始時,它只會加載FlaggedDates對象。但是,如果您訪問for循環內的相關對象,它將不會將這些對象加載到內存中。第一次嘗試檢索給定的FlaggedDate的scheduledSchools將導致新的數據庫往返檢索學校,或者由於您的上下文已被處置而拋出Exception。由於您要訪問for循環內的scheduledSchools集合,因此您需要爲for循環開始時加載的每個FlaggedDate執行一次新的數據庫往返。

效應初探以評論

禁用延遲加載是不一樣的啓用預先加載。在這個例子中:

context.ContextOptions.LazyLoadingEnabled = false; 
var schools = context.FlaggedDates.First().scheduledSchools; 

schools變量將包含一個空EntityCollection,因爲我在原來的查詢(FlaggedDates.First())沒有Include他們,我禁用延遲加載,使他們不能在初始查詢執行後加載。

您確定where d.dateID == 2意味着只有與該特定FlaggedDate對象相關的對象纔會被拉入。但是,根據與該FlaggedDate相關的對象的數量,您仍可能獲得大量數據通過電線。這是由於EntityFramework構建SQL查詢的方式。 SQL查詢結果始終爲表格格式,這意味着每行必須具有相同的列數。對於每個scheduledSchool對象,結果集中至少需要有一行,並且由於每行必須至少包含的某些值,因此最終將重複標記FlaggedDate對象上的每個標量值。因此,如果您有10個預定的學校和10個與您的FlaggedDate相關的訪談,則最終會有20個行,每個行包含FlaggedDate上的每個標量值。一半的行對於所有ScheduledSchool列將具有空值,而另一半對於所有的訪問列將具有空值。

但是,如果這樣做會變得非常糟糕,那就是如果您對包含的數據「深入」瞭解。例如,如果每個ScheduledSchool都有一個students屬性(您也包括在內),那麼突然之間,每個ScheduledSchool中的每個學生都會有一行,並且在每個這些行上,都會包含Student's ScheduledSchool的每個標量值(甚至儘管只有第一行的值最終被使用)以及原始FlaggedDate對象上的每個標量值。它可以快速加起來。

這很難以書面形式解釋,但是如果您查看多個Include的查詢返回的實際數據,則會看到有很多重複的數據。您可以使用LinqPad查看由EF代碼生成的SQL查詢。

+0

對於(1)(MY(1),我的意思是懶惰加載已啓用。該語句是一個加載的例子,因爲包含..對嗎? – Cynthia 2010-09-16 20:42:25

+0

對於(2)(MY(2))...如果延遲加載是DISABLED(換句話說,熱切加載是有效的),你是說導航屬性不會與FlaggedDates一起加載?那麼加載意味着什麼? – Cynthia 2010-09-16 20:44:00

+0

對你的編輯做出的反應:OK,我明白你在說什麼了。但是,對於你的觀點#1:所有的對象將被拉入,但只有在你的查詢中指定的,對嗎?例如,在我的例子中,我說d.dateID == 2,所以只有FlaggedDate對象的對象使用dateID = 2會將數據拉入。對嗎?只要你限制了查詢的範圍,那麼它就不會那麼貴。 – Cynthia 2010-09-16 20:51:01

0

沒有區別。在EF 1.0中這不是真的,它不支持急切的加載(至少不會自動加載)。在1.0中,您必須修改屬性以自動加載,或者在屬性引用上調用Load()方法。

有一點要記住的是,這些包括可以去灰飛煙滅,如果您在多個對象查詢,像這樣:

from d in ctx.ObjectDates.Include("MyObjectProperty") 
from da in d.Days 

ObjectDate.MyObjectProperty不會被自動加載。