Sự khác biệt giữa IQueryable <T> và IEnumerable <T> là gì?


Câu trả lời:


258

Trước hết, mở rộng các giao diện, vì vậy bất cứ điều gì bạn có thể làm với một "đồng bằng" , bạn cũng có thể làm với một .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>chỉ có một GetEnumerator()phương pháp mà trả về một Enumerator<T>mà bạn có thể gọi nó MoveNext()phương pháp để lặp qua một chuỗi các T .

IQueryable<T>đã mà IEnumerable<T> không có hai tính chất đặc biệt-một trong những điểm đến một nhà cung cấp truy vấn (ví dụ, một nhà cung cấp LINQ to SQL) và một trỏ từ một đến một biểu thức truy vấn đại diện cho các IQueryable<T>đối tượng như một cây cú pháp trừu tượng runtime-traversable có thể được được hiểu bởi nhà cung cấp truy vấn nhất định (đối với hầu hết các phần, bạn không thể đưa biểu thức LINQ to SQL cho nhà cung cấp LINQ cho Thực thể mà không bị ném ngoại lệ).

Biểu thức có thể chỉ đơn giản là một biểu thức không đổi của chính đối tượng hoặc một cây phức tạp hơn của một tập hợp các toán tử truy vấn và toán hạng. Các phương thức IQueryProvider.Execute()hoặc nhà cung cấp truy vấn IQueryProvider.CreateQuery()được gọi với một Biểu thức được truyền cho nó, và sau đó, một kết quả truy vấn hoặc một kết quả khác IQueryableđược trả về, tương ứng.


8
Có bất kỳ lợi ích nào khi sử dụng AsQueryable không?
Jordan

6
Lợi ích duy nhất là sự tiện lợi. AsQueryable()sẽ chỉ truyền một số đếm cho một truy vấn và trả về nó nếu nó thực hiện IQueryablegiao diện, nếu không nó sẽ bọc nó trong một ConstantExpression, được tham chiếu trong một EnumerableQueryđối tượng được trả về .
Mark Cidade

3
Câu hỏi liên quan: Làm rõ <T> và IQueryable <T>?
Christopher Stevenson

1
Đáng đọc bài viết này
JenonD

@JenonD liên kết là chết, đây là waybackmachine: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/...
majjam

201

Sự khác biệt chính là các toán tử LINQ để IQueryable<T>lấy Expressioncác đối tượng thay vì đại biểu, nghĩa là logic truy vấn tùy chỉnh mà nó nhận được, ví dụ: bộ chọn vị ngữ hoặc giá trị, ở dạng cây biểu thức thay vì ủy nhiệm cho một phương thức.

  • IEnumerable<T> là tuyệt vời để làm việc với các chuỗi được lặp trong bộ nhớ, nhưng
  • IQueryable<T> cho phép hết bộ nhớ những thứ như nguồn dữ liệu từ xa, chẳng hạn như cơ sở dữ liệu hoặc dịch vụ web.

Thực hiện truy vấn:

  • Trong đó việc thực hiện truy vấn sẽ được thực hiện "trong quá trình" , thông thường tất cả những gì được yêu cầu là mã (dưới dạng mã) để thực thi từng phần của truy vấn.

  • Trường hợp thực thi sẽ được thực hiện ngoài quy trình , logic của truy vấn phải được thể hiện trong dữ liệu để nhà cung cấp LINQ có thể chuyển đổi nó thành dạng thích hợp cho thực thi hết bộ nhớ - cho dù đó là truy vấn LDAP, SQL hoặc bất cứ điều gì.

Thêm trong:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
Tôi thích đề cập đến các hoạt động hết bộ nhớ. Nó làm rõ một sự khác biệt thực tế trong sử dụng.
Ishmael Smyrnow

2
Thay vì lấy các đại biểu làm tham số như phương thức IEnumerable <T> Where, IQueryable <T> sẽ lấy tham số Biểu thức <TDelegate>. Chúng tôi không chuyển mã vào IQueryable <T>, chúng tôi sẽ chuyển các cây biểu thức (mã dưới dạng dữ liệu) để nhà cung cấp LINQ phân tích. C # 3.0 và LINQ
Lu55

một cái gì đó có liên kết với hình ảnh của bạn, nó không hiển thị trong phần thân bài vì một số lý do codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey Tuy nhiên, tôi thấy hình ảnh đó chỉ tốt trong câu trả lời này: i.stack.imgur.com/2DAqv.jpg
VonC

190

Đây là một video hay trên youtube cho thấy các giao diện này khác nhau như thế nào, đáng xem.

Dưới đây đi một câu trả lời mô tả dài cho nó.

Điểm quan trọng đầu tiên cần nhớ là IQueryablegiao diện kế thừa từ IEnumerable, vì vậy bất cứ điều gì IEnumerablecó thể làm, IQueryablecũng có thể làm.

nhập mô tả hình ảnh ở đây

Có nhiều sự khác biệt nhưng chúng ta hãy thảo luận về một sự khác biệt lớn tạo nên sự khác biệt lớn nhất. IEnumerablegiao diện rất hữu ích khi bộ sưu tập của bạn được tải bằngLINQ khung Entity và bạn muốn áp dụng bộ lọc trên bộ sưu tập.

Hãy xem xét mã đơn giản dưới đây sử dụng IEnumerablevới khung thực thể. Đó là sử dụng một Wherebộ lọc để có được hồ sơ mà EmpId2.

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

Đây là nơi bộ lọc được thực thi ở phía máy khách có IEnumerablemã. Nói cách khác tất cả các dữ liệu được lấy từ cơ sở dữ liệu và sau đó tại client quét của nó và nhận được kỷ lục với EmpId2.

nhập mô tả hình ảnh ở đây

Nhưng bây giờ hãy xem đoạn mã dưới đây mà chúng tôi đã đổi IEnumerablethành IQueryable. Nó tạo ra một Truy vấn SQL ở phía máy chủ và chỉ có dữ liệu cần thiết được gửi đến phía máy khách.

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

nhập mô tả hình ảnh ở đây

Vì vậy, sự khác biệt giữa IQueryableIEnumerable là về nơi logic bộ lọc được thực thi. Một cái thực thi ở phía máy khách và cái kia thực thi trên cơ sở dữ liệu.

Vì vậy, nếu bạn chỉ làm việc với bộ sưu tập dữ liệu trong bộ nhớ IEnumerablelà một lựa chọn tốt nhưng nếu bạn muốn truy vấn bộ sưu tập dữ liệu được kết nối với cơ sở dữ liệu thì 'IQueryable là lựa chọn tốt hơn vì nó làm giảm lưu lượng mạng và sử dụng sức mạnh của ngôn ngữ SQL.


Xin chào, cảm ơn rất nhiều vì lời giải thích tuyệt vời. Tôi hiểu tại sao IQueryable là lựa chọn tốt hơn cho dữ liệu "hết bộ nhớ" nhưng tôi đang đấu tranh để hiểu tại sao IEnumerable lại tốt hơn cho dữ liệu "trong bộ nhớ"? Tôi vẫn nghĩ rằng tốt hơn là lấy dữ liệu được lọc hơn là lấy dữ liệu và áp dụng bộ lọc.
Imad

khi nó "trong bộ nhớ" thì nó không thực sự quan trọng. dữ liệu đã có trên bộ nhớ, vào thời gian chính xác nó được lọc không thành vấn đề.
Roni Axelrad

@Imad Ví dụ: chiếu dữ liệu bằng cách chuyển đổi thực thể DateTimePackset thành DateTime không thể thực hiện được bằng cách sử dụng IQueryable hoặc với EntityFifts. Cách tốt nhất là vào AsEnumerable () đối tượng thực thể, sau đó Chọn () vào chế độ xem có chứa DateTime. Quá trình này sử dụng các chức năng trong bộ nhớ.
Jeff Li

57

IEnumerable: IEnumerable phù hợp nhất để làm việc với bộ sưu tập trong bộ nhớ (hoặc truy vấn cục bộ). IEnumerable không di chuyển giữa các mục, nó chỉ là bộ sưu tập chuyển tiếp.

IQueryable: IQueryable phù hợp nhất với nguồn dữ liệu từ xa, như cơ sở dữ liệu hoặc dịch vụ web (hoặc truy vấn từ xa). IQueryable là một tính năng rất mạnh mẽ cho phép nhiều tình huống thực thi bị hoãn lại thú vị (như truy vấn phân trang và thành phần).

Vì vậy, khi bạn chỉ cần lặp lại qua bộ sưu tập trong bộ nhớ, hãy sử dụng IEnumerable, nếu bạn cần thực hiện bất kỳ thao tác nào với bộ sưu tập như Dataset và các nguồn dữ liệu khác, hãy sử dụng IQueryable


3
Không sử dụng IEnountable thực thi hoãn lại?
Ian Warburton

3
Việc thực thi hoãn lại có sẵn cả trong IEnumerable và IQueryable. Thông tin thú vị khác có thể được tìm thấy ở đây: stackoverflow.com/questions/2876616/
Kẻ

18

Nói một cách đơn giản, sự khác biệt lớn khác là IEnumerable thực hiện truy vấn chọn ở phía máy chủ, tải dữ liệu trong bộ nhớ ở phía máy khách và sau đó lọc dữ liệu trong khi IQueryable thực hiện chọn truy vấn ở phía máy chủ với tất cả các bộ lọc.


17

Trong cuộc sống thực, nếu bạn đang sử dụng ORM như LINQ-to-SQL

  • Nếu bạn tạo một IQueryable, thì truy vấn có thể được chuyển đổi thành sql và chạy trên máy chủ cơ sở dữ liệu
  • Nếu bạn tạo một IEnumerable, thì tất cả các hàng sẽ được kéo vào bộ nhớ dưới dạng các đối tượng trước khi chạy truy vấn.

Trong cả hai trường hợp nếu bạn không gọi một ToList()hoặc ToArray()sau đó truy vấn sẽ được thực thi mỗi khi nó được sử dụng, vì vậy, giả sử, bạn có mộtIQueryable<T> và bạn điền 4 hộp danh sách từ đó, thì truy vấn sẽ được chạy với cơ sở dữ liệu 4 lần.

Ngoài ra nếu bạn mở rộng truy vấn của mình:

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

Sau đó, với một IQueryable, SQL được tạo sẽ chứa trong đó có tên = trong đó là một tên, nhưng với một IE có vô số vai trò khác sẽ được lấy lại từ cơ sở dữ liệu, thì việc kiểm tra x.name = khăn sẽ được thực hiện bởi .NET.


10

IEnumerable đang tham chiếu đến một bộ sưu tập nhưng IQueryable chỉ là một truy vấn và nó sẽ được tạo bên trong Expression Tree.we sẽ chạy truy vấn này để lấy dữ liệu từ cơ sở dữ liệu.


8

Bài kiểm tra nhỏ được đề cập dưới đây có thể giúp bạn hiểu một khía cạnh khác biệt giữa IQueryable<T>IEnumerable<T>. Tôi đã sao chép câu trả lời này từ đây bài đăng , nơi tôi đang cố gắng thêm các chỉnh sửa vào bài đăng của người khác

Tôi đã tạo cấu trúc sau trong DB (tập lệnh DDL):

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

Đây là tập lệnh chèn bản ghi (tập lệnh 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

Bây giờ, mục tiêu của tôi chỉ đơn giản là lấy 2 bản ghi hàng đầu từ Employeebảng trong cơ sở dữ liệu. Tôi đã thêm một mục Mô hình dữ liệu thực thể ADO.NET vào ứng dụng bảng điều khiển của mình chỉ vàoEmployee bảng trong cơ sở dữ liệu của tôi và bắt đầu viết các truy vấn LINQ.

Mã cho tuyến đường 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);
    }
}

Khi tôi bắt đầu chạy chương trình này, tôi cũng đã bắt đầu một phiên trình hồ sơ truy vấn SQL trên phiên bản SQL Server của mình và đây là tóm tắt về thực thi:

  1. Tổng số truy vấn bị sa thải: 1
  2. Truy vấn văn bản: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

Nó chỉ IQueryableđủ thông minh để áp dụng Top (2)mệnh đề trên chính máy chủ cơ sở dữ liệu để nó chỉ mang lại 2 trên 5 bản ghi qua dây. Bất kỳ bộ lọc trong bộ nhớ nào nữa là không cần thiết ở phía máy khách.

Mã cho tuyến đường IEn Countable :

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);
    }
}

Tóm tắt thực hiện trong trường hợp này:

  1. Tổng số truy vấn bị sa thải: 1
  2. Truy vấn văn bản được ghi trong SQL profiler: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Bây giờ điều này được IEnumerablemang tất cả 5 bản ghi có trong Salarybảng và sau đó thực hiện lọc trong bộ nhớ trên máy khách để có được 2 bản ghi hàng đầu. Vì vậy, nhiều dữ liệu hơn (3 hồ sơ bổ sung trong trường hợp này) đã được chuyển qua dây không cần thiết.


7

Đây là những gì tôi đã viết trên một bài tương tự (về chủ đề này). (Và không, tôi thường không trích dẫn bản thân mình, nhưng đây là những bài viết rất hay.)

"Bài viết này rất hữu ích: IQueryable vs IEnumerable trong LINQ-to-SQL .

Trích dẫn bài viết đó, 'Theo tài liệu MSDN, các cuộc gọi được thực hiện trên IQueryable hoạt động bằng cách xây dựng cây biểu thức nội bộ thay thế. "Các phương thức mở rộng IQueryable (Of T) này không thực hiện bất kỳ truy vấn trực tiếp nào. Thay vào đó, chức năng của chúng là xây dựng một đối tượng Biểu thức, là một cây biểu thức đại diện cho truy vấn tích lũy." '

Cây biểu thức là một cấu trúc rất quan trọng trong C # và trên nền tảng .NET. (Nói chung chúng rất quan trọng, nhưng C # làm cho chúng rất hữu ích.) Để hiểu rõ hơn về sự khác biệt, tôi khuyên bạn nên đọc về sự khác biệt giữa các biểu thứccâu lệnh trong đặc tả C # 5.0 chính thức ở đây. Đối với các khái niệm lý thuyết nâng cao phân nhánh vào phép tính lambda, các biểu thức cho phép hỗ trợ cho các phương thức như các đối tượng hạng nhất. Sự khác biệt giữa IQueryable và IEnumerable tập trung vào điểm này. IQueryable xây dựng các cây biểu thức trong khi IEnumerable thì không, ít nhất là về mặt chung cho những người trong chúng ta không làm việc trong các phòng thí nghiệm bí mật của Microsoft.

Dưới đây là một bài viết rất hữu ích khác, chi tiết về sự khác biệt từ quan điểm đẩy so với kéo. (Bằng cách "đẩy" so với "kéo", tôi đang đề cập đến hướng của luồng dữ liệu. Kỹ thuật lập trình phản ứng cho .NET và C #

Dưới đây là một bài viết rất hay, chi tiết về sự khác biệt giữa lambdas tuyên bố và lambdas biểu thức và thảo luận về các khái niệm về biểu thức tress sâu hơn: Xem xét lại các đại biểu C #, cây biểu thức và câu lệnh lambda so với biểu thức lambda. . "


6

Chúng tôi sử dụng IEnumerableIQueryableđể thao tác dữ liệu được lấy từ cơ sở dữ liệu. IQueryablekế thừa từ IEnumerable, do đó, IQueryablecó chứa tất cả các IEnumerabletính năng. Sự khác biệt chính giữa IQueryableIEnumerableIQueryablethực thi truy vấn với các bộ lọc trong khi IEnumerablethực hiện truy vấn trước và sau đó nó lọc dữ liệu dựa trên các điều kiện.

Tìm sự khác biệt chi tiết hơn dưới đây:

Vô số

  1. IEnumerabletồn tại trong System.Collectionskhông gian tên
  2. IEnumerable thực hiện một truy vấn chọn ở phía máy chủ, tải dữ liệu trong bộ nhớ ở phía máy khách và sau đó lọc dữ liệu
  3. IEnumerable phù hợp để truy vấn dữ liệu từ các bộ sưu tập trong bộ nhớ như List, Array
  4. IEnumerable có lợi cho các truy vấn LINQ to Object và LINQ to XML

Truy vấn

  1. IQueryabletồn tại trong System.Linqkhông gian tên
  2. IQueryable thực hiện một 'truy vấn chọn' ở phía máy chủ với tất cả các bộ lọc
  3. IQueryable phù hợp để truy vấn dữ liệu từ các bộ sưu tập ngoài bộ nhớ (như cơ sở dữ liệu, dịch vụ)
  4. IQueryable có lợi cho các truy vấn LINQ to SQL

Vì vậy, IEnumerablethường được sử dụng để xử lý bộ sưu tập trong bộ nhớ, trong khi đó, IQueryablethường được sử dụng để thao tác các bộ sưu tập.



2

IQueryable nhanh hơn IEnumerable nếu chúng ta đang xử lý một lượng dữ liệu khổng lồ từ cơ sở dữ liệu bởi vì, IQueryable chỉ nhận được dữ liệu cần thiết từ cơ sở dữ liệu trong đó IEnumerable có được tất cả dữ liệu bất kể sự cần thiết từ cơ sở dữ liệu


0

ienumerable: khi chúng ta muốn xử lý bộ nhớ trong tiến trình, tức là không có kết nối dữ liệu iqueryable: khi nào xử lý máy chủ sql, tức là với ilist kết nối dữ liệu: các hoạt động như thêm đối tượng, xóa đối tượng, v.v.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.