Sự khác biệt giữa IQueryable<T>
và là IEnumerable<T>
gì?
Xem thêm Sự khác biệt giữa IQueryable và IEnumerable trùng lặp với câu hỏi này.
Sự khác biệt giữa IQueryable<T>
và là IEnumerable<T>
gì?
Xem thêm Sự khác biệt giữa IQueryable và IEnumerable trùng lặp với câu hỏi này.
Câu trả lời:
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 .
Gì 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.
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 IQueryable
giao 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ề .
Sự khác biệt chính là các toán tử LINQ để IQueryable<T>
lấy Expression
cá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.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:
Đâ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à IQueryable
giao diện kế thừa từ IEnumerable
, vì vậy bất cứ điều gì IEnumerable
có thể làm, IQueryable
cũng có thể làm.
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. IEnumerable
giao 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 IEnumerable
với khung thực thể. Đó là sử dụng một Where
bộ lọc để có được hồ sơ mà EmpId
là 2
.
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ó IEnumerable
mã. 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 EmpId
là 2
.
Nhưng bây giờ hãy xem đoạn mã dưới đây mà chúng tôi đã đổi IEnumerable
thà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>();
Vì vậy, sự khác biệt giữa IQueryable
vàIEnumerable
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ớ IEnumerable
là 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.
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
Trong cuộc sống thực, nếu bạn đang sử dụng ORM như LINQ-to-SQL
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.
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>
và 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ừ Employee
bả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:
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:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Bây giờ điều này được IEnumerable
mang tất cả 5 bản ghi có trong Salary
bả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.
Đâ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ức và câ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. . "
Chúng tôi sử dụng IEnumerable
và IQueryable
để thao tác dữ liệu được lấy từ cơ sở dữ liệu. IQueryable
kế thừa từ IEnumerable
, do đó, IQueryable
có chứa tất cả các IEnumerable
tính năng. Sự khác biệt chính giữa IQueryable
và IEnumerable
là IQueryable
thực thi truy vấn với các bộ lọc trong khi IEnumerable
thự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ố
IEnumerable
tồn tại trong System.Collections
không gian tênIEnumerable
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ệuIEnumerable
phù hợp để truy vấn dữ liệu từ các bộ sưu tập trong bộ nhớ như List, ArrayIEnumerable
có lợi cho các truy vấn LINQ to Object và LINQ to XMLTruy vấn
IQueryable
tồn tại trong System.Linq
không gian tênIQueryable
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ọcIQueryable
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ụ)IQueryable
có lợi cho các truy vấn LINQ to SQLVì vậy, IEnumerable
thường được sử dụng để xử lý bộ sưu tập trong bộ nhớ, trong khi đó, IQueryable
thường được sử dụng để thao tác các bộ sưu tập.
Cả IEnumerable và IQueryable đều được sử dụng để giữ bộ sưu tập dữ liệu và thực hiện thao tác thao tác dữ liệu, ví dụ như lọc trên bộ sưu tập dữ liệu. Ở đây bạn có thể tìm thấy sự so sánh khác biệt tốt nhất với ví dụ. http://www.gurujipoint.com/2017/05/difference-b between-enumerable-and.html
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.