簡體   English   中英

在Linq和Exe Time中使用ToList()

[英]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包含哪些內容? 由於查詢尚未執行?

有三個階段需要了解。

  1. 首先,創建查詢時。
  2. 其次,迭代查詢變量時(延遲執行)。
  3. 第三,強制查詢即時結果。

    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的返回值。 第一組是諸如WhereSelectJoinGroupBy 它們都返回某種IQueryable。

只要連接該組的功能,表達式就會更改。 該查詢尚未執行。 返回值仍然是表示查詢能力的對象。 這些函數使用延遲執行 (或延遲執行),這意味着查詢尚未執行。 您會認識到這些函數,因為它們返回IQueryable<...> 這些功能的說明的備注部分還提到推遲執行。

僅在直接或間接使用foreach調用GetEnumerator() / MoveNext() ,才執行查詢。

如果您開始枚舉,則將Expression發送給Provider ,后者將Expression轉換為查詢執行者可以理解的語言(SQL),並命令執行者執行查詢。 將獲取的數據轉換為IEnumerable<...> ,然后將其枚舉為好像數據是本地的。

這多少取決於提供程序的提供者,但有時提供程序確實很聰明。 它不會從您的產品數據庫中獲取所有數百萬個產品,但會獲取一個產品頁面。 當您枚舉此頁面時,提供程序將獲取下一頁。 這將提高處理速度,因為不會獲取比您實際使用的更多的產品,而且您可以在獲取所有產品之前開始枚舉。

我提到了使用延遲執行的LINQ函數(=返回IQueryable)。 另一組函數將執行查詢。 這組函數包含ToListToDictionaryMaxFirstOrDefaultCount類的函數,它們不返回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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM