[英]Use ToList() in Linq and Exe Time
以下是我的教科書中的一個示例:
var allGenres = from genre in myEntities.Genres.Include("Reviews")
orderby genre.Name
select new { genre.Name, genre.Reviews };
Repeater1.DataSource = allGenres.ToList();
Repeater1.DataBind();
書說:
調用ToList()后,將立即執行查詢,並從數據庫中檢索相關體裁和評論並將其分配給DataSource屬性
所以我的問題是,如果我擺脫了Repeater1.DataSource = allGenres.ToList();
,var allGenres包含哪些內容? 由於查詢尚未執行?
有三個階段需要了解。
第三,強制查詢即時結果。
var allGenres = from genre in myEntities.Genres.Include("Reviews") orderby genre.Name select new { genre.Name, genre.Reviews };
在此代碼中,僅創建查詢。 它作為一個人在墓地里死了。 如果需要延遲執行,則可以使用for循環等遍歷結果。
要強制立即執行,可以使用轉換運算符,例如
ToList, ToArray, ToLookup, and ToDictionary.
希望能幫助到你。
您可以在此行上放置一個斷點:
var allGenres = from genre in myEntities.Genres.Include("Reviews")
orderby genre.Name
select new { genre.Name, genre.Reviews };
並注意到沒有任何反應。 在以下行之后, voila SQL Profiler將顯示正在發生的sql查詢:
Repeater1.DataSource = allGenres.ToList();
您的對象allGenres
是實現IQueryable<...>
的對象。 這意味着它代表一個序列,並且具有獲取該序列的第一個元素的功能,一旦獲得了該元素,就可以獲取下一個,直到沒有其他元素為止。
<...>
部分定義序列中的元素類型。 因此, IQueryable<Book>
表示您可以查詢一系列Books
,可以依次枚舉。 序列中的每個元素都是Book
類的對象
使用IQueryable的基本接口,即IEnumerable<Book>
提供此枚舉。
在最低級別上,此枚舉按如下方式進行:
IEnumerable<Book> books = ... // for example new List<Book>(), or new Book[10]
IEnumerator<Book> bookEnumerator = books.Getenumerator();
// as long as there are books, print the title:
// the first MoveNext() moves to the first element
// every other MoveNext() move to the next element
// it returns false if there is no such element (no first, or no next)
while (bookEnumerator.MoveNext())
{
// the enumerator points to the next element. Property Current contains this element
Book book = bookEnumerator.Current;
Console.WriteLine(book.Title);
}
通常,我們不會使用這種低級功能。 您會更經常地看到foreach變量:
foreach (Book book in books)
{
Console.WriteLine(book.Title);
}
foreach
將為您執行GetEnumerator()
/ MoveNext()
/ Current
請注意, IEnumerable
並不表示枚舉本身,而是表示枚舉的能力 。 人們經常沒有那么精確,並且將IEnumerable稱為序列本身。 但是請記住:要訪問序列的元素,您需要枚舉它們(通過使用MoveNext或通過調用foreach)。
IQueryable<...>
與IEnumerable<...>
非常相似。 不同之處在於,通常它是指由不同的進程處理,例如數據庫管理系統或另一台計算機上的服務器,它也可以表示CSV文件中的行或其他內容。 IQueryable的目的是將數據的獲取方式與對獲取的數據的操作分開。
就像IEnumerable擁有枚舉功能一樣 , IQueryable擁有查詢數據的功能 。
為此, IQueryable
具有一個Expression
和一個Provider
。 Expression
以通用方式定義必須獲取哪些數據。 Provider
知道誰必須提供數據(數據庫),以及該數據提供者需要哪種語言(SQL)。
也許您已經注意到有兩種LINQ語句。 返回IQueryable的返回值和不返回IQueryable的返回值。 第一組是諸如Where
, Select
, Join
, GroupBy
。 它們都返回某種IQueryable。
只要連接該組的功能,表達式就會更改。 該查詢尚未執行。 返回值仍然是表示查詢能力的對象。 這些函數使用延遲執行 (或延遲執行),這意味着查詢尚未執行。 您會認識到這些函數,因為它們返回IQueryable<...>
。 這些功能的說明的備注部分還提到推遲執行。
僅在直接或間接使用foreach
調用GetEnumerator()
/ MoveNext()
,才執行查詢。
如果您開始枚舉,則將Expression
發送給Provider
,后者將Expression
轉換為查詢執行者可以理解的語言(SQL),並命令執行者執行查詢。 將獲取的數據轉換為IEnumerable<...>
,然后將其枚舉為好像數據是本地的。
這多少取決於提供程序的提供者,但有時提供程序確實很聰明。 它不會從您的產品數據庫中獲取所有數百萬個產品,但會獲取一個產品頁面。 當您枚舉此頁面時,提供程序將獲取下一頁。 這將提高處理速度,因為不會獲取比您實際使用的更多的產品,而且您可以在獲取所有產品之前開始枚舉。
我提到了使用延遲執行的LINQ函數(=返回IQueryable)。 另一組函數將執行查詢。 這組函數包含ToList
, ToDictionary
, Max
, FirstOrDefault
, Count
類的函數,它們不返回IQueryable<...>
,但返回TResult
。 如果您查看源代碼(google為“參考源可查詢目錄”的Google),您會發現他們將通過調用foreach或GetEnumerator來做到這一點。
因為必須將Expression
轉換為SQL,所以查詢的可能性比IEnumerable<...>
。 例如,您不能在查詢中使用任何本地定義的方法。 如果這樣做,執行查詢后,您將立即獲得運行時異常,告訴您不能將表達式轉換為SQL。
可以執行哪種表達式取決於必須執行查詢的人員。 列出了關於ling-to-entities的LINQ支持和不支持的方法 。
如果使用的是實體框架,則allGeneres將是IQueryable<Genre>
接口的實例。 該行為稱為延遲執行。 有關更多參考https://docs.microsoft.com/zh-cn/dotnet/framework/data/adonet/ef/language-reference/query-execution#deferred-query-execution
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.