[.net] IQueryable <T>和IEnumerable <T>有什麼區別?



5 Answers

主要區別在於用於IQueryable<T>的LINQ運算符使用Expression對象而不是委託,這意味著它接收的自定義查詢邏輯(例如謂詞或值選擇器)以表達式樹的形式而不是委託給方法。

  • IEnumerable<T>非常適合用於在內存中迭代的序列,但是
  • IQueryable<T>允許像遠程數據源(如數據庫或Web服務)的內存不足。

查詢執行:

  • 在查詢的執行將“在進行中”的情況下 ,通常所需要的是執行查詢的每個部分的代碼(作為代碼)。

  • 如果執行將在進程外執行,則查詢的邏輯必須用數據表示,以便LINQ提供程序可以將其轉換為適用於內存不足執行的適當形式 - 無論是LDAP查詢, SQL或其他。

更多信息:

Question

IQueryable<T>IEnumerable<T>什麼區別?

另請參見與此問題重疊的IQueryable和IEnumerable之間的區別







在現實生活中,如果您使用的是像LINQ到SQL這樣的ORM

  • 如果您創建了IQueryable,那麼查詢可能會轉換為sql並在數據庫服務器上運行
  • 如果您創建IEnumerable,那麼在運行查詢之前,所有行都將作為對象拉入內存。

在這兩種情況下,如果您不調用ToList()ToArray()則每次使用時都會執行查詢,因此,例如,您有一個IQueryable<T>並從中填充4個列錶框,然後查詢將針對數據庫運行4次。

此外,如果你擴展你的查詢:

q.Where(x.name = "a").ToList()

然後,使用IQueryable生成的SQL將包含“where name =”a“,但使用IEnumerable時,將從數據庫中拉出更多角色,然後x.name =”a“檢查將由.NET完成。




IEnumerable: IEnumerable最適合處理內存中的集合(或本地查詢)。 IEnumerable不會在項目之間移動,它只是向前收集。

IQueryable: IQueryable最適合於遠程數據源,如數據庫或Web服務(或遠程查詢)。 IQueryable是一個非常強大的功能,支持各種有趣的延遲執行方案(如分頁和基於合成的查詢)。

因此,當您只需遍歷內存集合時,使用IEnumerable,如果您需要對集合(如Dataset和其他數據源)執行任何操作,請使用IQueryable




下面提到的小測試可能會幫助您理解IQueryable<T>IEnumerable<T>之間差異的一個方面。 我從this文章中轉載了這個答案,我試圖在其他人的帖子中添加更正

我在DB(DDL腳本)中創建了以下結構:

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

這是記錄插入腳本(DML腳本):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

現在,我的目標是簡單地從數據庫中的Employee表中獲取前兩條記錄。 我在我的控制台應用程序中添加了一個ADO.NET實體數據模型項,指向我數據庫中的Employee表,並開始編寫LINQ查詢。

IQueryable路由代碼

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

當我開始運行這個程序時,我還在SQL Server實例上啟動了一個SQL Query分析器會話,這裡是執行摘要:

  1. 查詢總數:1
  2. 查詢文本: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

只是IQueryable足夠聰明,能夠在數據庫服務器端自身應用Top (2)子句,因此它只能通過線路傳輸5個記錄中的2個。 客戶端計算機端不需要任何進一步的內存過濾。

IEnumerable路由的代碼

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

這種情況下的執行摘要:

  1. 查詢總數:1
  2. 查詢在SQL事件探查器中捕獲的文本: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

現在的事情是IEnumerable帶來了Salary表中的所有5條記錄,然後在客戶端計算機上執行了內存過濾以獲得最高2條記錄。 因此,更多的數據(在這種情況下是3個額外的記錄)通過電線不必要地傳輸。




ienumerable:當我們要處理進程內存,即沒有數據連接時iqueryable:何時處理sql server,即與數據連接ilist:操作如添加對象,刪除對像等






Related