請注明轉載地址:http://www.cnblogs.com/arhat
在上一章中,我們使用了Linq對Entity Framework進行了一個查詢,但是通過學習我們卻發現了懶加載給我來的性能上的開銷是很到的,尤其是在循環中,如果數據量不是很多的情況下還可以接受,如果數據量一旦大氣來,那么這個效率則是影響非常大的。那該怎么辦呢?其實在Entity Framwork中,除了提供了懶加載技術還提供了一個“貪婪加載”。那么什么是貪婪加載呢?從名字上看,就是非常的粗魯的,一次性的吧相關的數據全部查詢出來,雖然在性能上說還是有點影響的,但是比起在循環中使用懶加載要強了不少了啊。
下面呢,老魏先不說懶加載的知識,把上一張遺留的一個查詢給家說一下,順便以這個例子和貪婪加載做一下對比。
Demo3:查詢班級的信息,還要得到此班級中的學生。
SQL:
select a.* ,b.* from clazz as a left join student as b on a.CId = b.CId
Linq:
DAL.SchoolContext context = new DAL.SchoolContext(); var query = from clazz in context.Clazz select clazz; foreach (var clazz in query) { Console.WriteLine(clazz.CName); if (clazz.Students != null && clazz.Students.Count > 0) { foreach(var student in clazz.Students) { Console.WriteLine("---該班的學生:" + student.SName); } } }
翻譯SQL:在執行中翻譯的SQL
這里老魏截圖了,就是因為在循環中使用懶加載而產生了n多個查詢語句,但是
總體上兩個SQL語句:
1,查詢出clazz信息的SQL
SELECT [Extent1].[CId] AS [CId], [Extent1].[CName] AS [CName] FROM [dbo].[Clazz] AS [Extent1]
2,根據懶加載而產生的SQL語句(被重復了N次)
exec sp_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
雖然我們通過懶加載可以達到我們想要的效果,但是在效率上是無法忍受的尤其是在數據多的情況下。
那么Entity Framework也想到了這問題,因為所有的ORM框架都有懶加載,使用起來的確的方便,但是也是在改用的時候用,尤其在循環中就更不應該使用了。所以這里呢,老魏有個建議,就是在循環中千萬不要使用懶加載。既然在循環中不能使用懶加載那么該怎么辦呢?這就要利用Entity Framework給我們提供的貪婪加載。下面看以下代碼,然后老魏在來解釋一下。把上面的代碼改為如下的代碼:
DAL.SchoolContext context = new DAL.SchoolContext(); //取消懶加載目的是為了做實驗看能夠一次加載完數據 context.Configuration.LazyLoadingEnabled = false; var query = from clazz in context.Clazz.Include("Students") select clazz; foreach (var clazz in query) { Console.WriteLine(clazz.CName); if (clazz.Students != null && clazz.Students.Count > 0) { foreach(var student in clazz.Students) { Console.WriteLine("---該班的學生:" + student.SName); } } }
運行一下,同時監控一下SQL Server的狀態。首先是翻譯的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], CASE WHEN ([Extent2].[SId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] FROM [dbo].[Clazz] AS [Extent1] LEFT OUTER JOIN [dbo].[Student] AS [Extent2] ON [Extent1].[CId] = [Extent2].[CId] ) AS [Project1] ORDER BY [Project1].[CId] ASC, [Project1].[C1] ASC
SQL Server狀態:
發現在執行的過程中,循環語句並沒有的發出額外的指令,只是用來上面翻譯的SQL。但是結果卻是一樣的。
無非就是在Linq中加入了一個Include()方法。這個方法就是用來開啟貪婪加載的主要方法。意思是說在加載查詢對象的時候。把查詢對象的關聯數據也查詢出來。其實這里面是有陷阱的。當然這陷阱值得是Include的參數。顧名思義,和clazz管理的是student對象,那么在參數就是”Student”。其實不然,因為根據Include參數的含義是說“路徑”。那么這個路徑是什么呢?其實就是”導航屬性的名字“。在clazz中有一個導航屬性是Students,則在Include中也要使用這個名字。
當然了,如果大家想的到的話,那么和Student關聯的對象能夠查詢出來呢?答案是肯定的,如果關聯屬性有多個則使用”.”來連接。比如我們可以把代碼改為如下的樣子:
var query = from clazz in context.Clazz.Include("Students.Student_Courses.Courses") select clazz;
那我們在查詢clazz對象的也查出來了student,course的信息。其實看到這里大家就知道了貪婪加載雖然沒有在循環中那么的消耗性能,但是一次性查詢的數據是很多的,還是有影響的,但是沒有懶加載那么厲害了。
總結一下,如果要在循環中使用數據,請使用貪婪加載,否則使用懶加載。本章就到這里了。希望大家能夠頂一下!謝謝了。