在上一章中,我們使用了Linq對Entity Framework進行了一個查詢,但是通過學習我們卻發(fā)現(xiàn)了懶加載給我來的性能上的開銷是很到的,尤其是在循環(huán)中,如果數(shù)據(jù)量不是很多的情況下還可以接受,如果數(shù)據(jù)量一旦大氣來,那么這個效率則是影響非常大的。那該怎么辦呢?其實在Entity Framwork中,除了提供了懶加載技術還提供了一個“貪婪加載”。那么什么是貪婪加載呢?從名字上看,就是非常的粗魯?shù)?,一次性的吧相關的數(shù)據(jù)全部查詢出來,雖然在性能上說還是有點影響的,但是比起在循環(huán)中使用懶加載要強了不少了啊。
下面呢,老魏先不說懶加載的知識,把上一張遺留的一個查詢給家說一下,順便以這個例子和貪婪加載做一下對比。
Demo3:查詢班級的信息,還要得到此班級中的學生。
SQL:
selecta.*,b.*fromclazzasaleftjoinstudentas bona.CId=b.CId
Linq:
DAL.SchoolContext context =new DAL.SchoolContext();varquery =fromclazzin context.Clazzselect clazz;foreach(varclazzin query)
{
? ? ? Console.WriteLine(clazz.CName);if(clazz.Students !=null&& clazz.Students.Count >0)
? {? ? ? ? foreach(varstudentin clazz.Students)
? ? ? ? {
? ? ? ? ? Console.WriteLine("---該班的學生:"+ student.SName);
? ? ? }
? }
}
翻譯SQL:在執(zhí)行中翻譯的SQL

這里老魏截圖了,就是因為在循環(huán)中使用懶加載而產(chǎn)生了n多個查詢語句,但是

總體上兩個SQL語句:
1,查詢出clazz信息的SQL
SELECT[Extent1].[CId]AS[CId],
? ? [Extent1].[CName]AS[CName]FROM[dbo].[Clazz]AS[Extent1]
2,根據(jù)懶加載而產(chǎn)生的SQL語句(被重復了N次)
execsp_executesql N'SELECT
? ? [Extent1].[SId] AS [SId],
? ? [Extent1].[SName] AS [SName],
? ? [Extent1].[SAge] AS [SAge],
? ? [Extent1].[SMail] AS [SMail],
? ? [Extent1].[CId] AS [CId]
? ? FROM [dbo].[Student] AS [Extent1]
? ? WHERE [Extent1].[CId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=2
雖然我們通過懶加載可以達到我們想要的效果,但是在效率上是無法忍受的尤其是在數(shù)據(jù)多的情況下。
那么Entity Framework也想到了這問題,因為所有的ORM框架都有懶加載,使用起來的確的方便,但是也是在改用的時候用,尤其在循環(huán)中就更不應該使用了。所以這里呢,老魏有個建議,就是在循環(huán)中千萬不要使用懶加載。既然在循環(huán)中不能使用懶加載那么該怎么辦呢?這就要利用Entity Framework給我們提供的貪婪加載。下面看以下代碼,然后老魏在來解釋一下。把上面的代碼改為如下的代碼:
DAL.SchoolContext context =new DAL.SchoolContext();//取消懶加載目的是為了做實驗看能夠一次加載完數(shù)據(jù)context.Configuration.LazyLoadingEnabled =false;varquery =fromclazzincontext.Clazz.Include("Students")select clazz;foreach(varclazzin query)
{
? ? ? ? ? Console.WriteLine(clazz.CName);? ? ? ? ? if(clazz.Students !=null&& clazz.Students.Count >0)
? ? ? ? ? {? ? ? ? ? ? ? foreach(varstudentin clazz.Students)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Console.WriteLine("---該班的學生:"+ student.SName);
? ? ? ? ? ? ? }
? ? ? ? }
}
運行一下,同時監(jiān)控一下SQL Server的狀態(tài)。首先是翻譯的SQL:
SELECT[Project1].[CId]AS[CId],
? ? [Project1].[CName]AS[CName],
? ? [Project1].[C1]AS[C1],
? ? [Project1].[SId]AS[SId],
? ? [Project1].[SName]AS[SName],
? ? [Project1].[SAge]AS[SAge],
? ? [Project1].[SMail]AS[SMail],
? ? [Project1].[CId1]AS[CId1]FROM(SELECT[Extent1].[CId]AS[CId],
? ? ? ? [Extent1].[CName]AS[CName],
? ? ? ? [Extent2].[SId]AS[SId],
? ? ? ? [Extent2].[SName]AS[SName],
? ? ? ? [Extent2].[SAge]AS[SAge],
? ? ? ? [Extent2].[SMail]AS[SMail],
? ? ? ? [Extent2].[CId]AS[CId1],
? ? ? ? CASEWHEN([Extent2].[SId]ISNULL)THENCAST(NULLASint)ELSE1ENDAS[C1]FROM[dbo].[Clazz]AS[Extent1]LEFTOUTERJOIN[dbo].[Student]AS[Extent2]ON[Extent1].[CId]=[Extent2].[CId]? ? )? AS[Project1]ORDERBY[Project1].[CId]ASC,[Project1].[C1]ASC
SQL Server狀態(tài):

發(fā)現(xiàn)在執(zhí)行的過程中,循環(huán)語句并沒有的發(fā)出額外的指令,只是用來上面翻譯的SQL。但是結果卻是一樣的。

無非就是在Linq中加入了一個Include()方法。這個方法就是用來開啟貪婪加載的主要方法。意思是說在加載查詢對象的時候。把查詢對象的關聯(lián)數(shù)據(jù)也查詢出來。其實這里面是有陷阱的。當然這陷阱值得是Include的參數(shù)。顧名思義,和clazz管理的是student對象,那么在參數(shù)就是”Student”。其實不然,因為根據(jù)Include參數(shù)的含義是說“路徑”。那么這個路徑是什么呢?其實就是”導航屬性的名字“。在clazz中有一個導航屬性是Students,則在Include中也要使用這個名字。
當然了,如果大家想的到的話,那么和Student關聯(lián)的對象能夠查詢出來呢?答案是肯定的,如果關聯(lián)屬性有多個則使用”.”來連接。比如我們可以把代碼改為如下的樣子:
varquery =fromclazzincontext.Clazz.Include("Students.Student_Courses.Courses")? ? ? ? ? ? ? ? selectclazz;
那我們在查詢clazz對象的也查出來了student,course的信息。其實看到這里大家就知道了貪婪加載雖然沒有在循環(huán)中那么的消耗性能,但是一次性查詢的數(shù)據(jù)是很多的,還是有影響的,但是沒有懶加載那么厲害了。
總結一下,如果要在循環(huán)中使用數(shù)據(jù),請使用貪婪加載,否則使用懶加載。