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


Câu trả lời:


186

IEnumerable<T>đại diện cho một con trỏ chỉ về phía trước của T. .NET 3.5 đã thêm các phương thức mở rộng bao gồm LINQ standard query operatorstương tự WhereFirst, với bất kỳ toán tử nào yêu cầu các biến vị ngữ hoặc hàm ẩn danh Func<T>.

IQueryable<T>thực hiện cùng các toán tử truy vấn tiêu chuẩn LINQ, nhưng chấp nhận Expression<Func<T>>các biến vị ngữ và hàm ẩn danh. Expression<T>là một cây biểu thức được biên dịch, một phiên bản chia nhỏ của phương thức ("được biên dịch một nửa" nếu bạn muốn) có thể được phân tích cú pháp bởi nhà cung cấp truy vấn và được sử dụng theo đó.

Ví dụ:

IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

Trong khối đầu tiên, x => x.Age > 18là một phương thức ẩn danh ( Func<Person, bool>), có thể được thực thi như bất kỳ phương thức nào khác. Enumerable.Wheresẽ thực thi phương thức một lần cho mỗi người, lấy yieldcác giá trị mà phương thức trả về true.

Trong khối thứ hai, x => x.Age > 18là một cây biểu thức ( Expression<Func<Person, bool>>), có thể được coi là "là thuộc tính 'Tuổi'> 18".

Điều này cho phép những thứ như LINQ-to-SQL tồn tại bởi vì chúng có thể phân tích cây biểu thức và chuyển đổi nó thành SQL tương đương. Và bởi vì nhà cung cấp không cần thực thi cho đến khi IQueryableđược liệt kê (rốt cuộc, nó thực hiện IEnumerable<T>), nên nó có thể kết hợp nhiều toán tử truy vấn (trong ví dụ trên WhereFirstOrDefault) để đưa ra các lựa chọn thông minh hơn về cách thực hiện toàn bộ truy vấn đối với dữ liệu cơ bản nguồn (như sử dụng SELECT TOP 1trong SQL).

Xem:


1
câu trả lời khá ngắn gọn
ashveli

83

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ột IQueryablevà 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.Select(x.name = "a").ToList()

Sau đó, với một IQueryableSQL được tạo sẽ chứa where name = "a", nhưng với IEnumerablenhiều vai trò khác sẽ được lấy lại từ cơ sở dữ liệu, thì việc x.name = "a"kiểm tra sẽ được .NET thực hiện.


"truy vấn có thể được chuyển đổi thành sql": Tôi không nhận được 'có thể'. Ngoài ra, nếu tôi có IEnumerable và tạo một 'chuỗi phức tạp' thì (rõ ràng) không giống như IQueryable, nó sẽ không được dịch thành truy vấn SQL 'được tối ưu hóa'. Chỉ muốn xác nhận ý nghĩa của nó khi bạn nói 'tất cả các hàng sẽ được kéo vào bộ nhớ'. Hãy để chúng tôi nói rằng tôi có hai mệnh đề, sau đó tất cả các bộ dữ liệu của các thực thể sẽ được nạp vào bộ nhớ và sau đó quá trình lọc 'trong bộ nhớ' bình thường sẽ xảy ra?
Vaibhav

36

"Sự khác biệt chính là các phương thức mở rộng được xác định cho các đối tượng Biểu thức lấy IQueryable thay vì các đối tượng Func, nghĩa là đại biểu mà nó nhận được là một cây biểu thức thay vì một phương thức để gọi. IEnumerable rất tuyệt khi làm việc với các bộ sưu tập trong bộ nhớ, nhưng IQueryable cho phép cho một nguồn dữ liệu từ xa, như cơ sở dữ liệu hoặc dịch vụ web "

Nguồn: tại đây


19

IEnumerable IEnumerable phù hợp nhất để làm việc với bộ sưu tập trong bộ nhớ. 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 Phù hợp nhất với IQueryable cho nguồn dữ liệu từ xa, như cơ sở dữ liệu hoặc dịch vụ web. 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


11

Sự khác biệt về nguyên tắc là IEnumerable sẽ liệt kê tất cả các phần tử của nó mọi lúc, trong khi IQueryable sẽ liệt kê các phần tử hoặc thậm chí làm các việc khác, dựa trên truy vấn. Truy vấn là một Biểu thức (biểu diễn dữ liệu của mã .Net), mà IQueryProvider phải khám phá / giải thích / biên dịch / bất cứ điều gì để tạo kết quả.

Có một biểu thức truy vấn cho hai lợi thế.

Ưu điểm đầu tiên là tối ưu hóa. Vì các công cụ sửa đổi như 'Trường hợp' được bao gồm trong biểu thức truy vấn, IQueryProvider có thể áp dụng các tối ưu hóa không thể khác. Thay vì trả lại tất cả các phần tử sau đó loại bỏ hầu hết các phần tử do mệnh đề 'Trường hợp', nhà cung cấp có thể sử dụng bảng băm để định vị các mục bằng một khóa đã cho.

Ưu điểm thứ hai là tính linh hoạt. Vì Biểu thức là cấu trúc dữ liệu có thể khám phá, bạn có thể thực hiện những việc như tuần tự hóa truy vấn và gửi nó đến một máy từ xa (ví dụ: linq-to-sql).



1

Đầu tiên IEnumerable được tìm thấy trong Không gian tên System.Collections trong khi IQueryable được tìm thấy trong Không gian tên System.Linq. Nếu bạn đang sử dụng IEnumerable khi truy vấn dữ liệu từ các bộ sưu tập trong bộ nhớ như List, Array Collection, v.v. Và khi 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ụ), do đó bạn đang sử dụng IQueryable. Bởi vì Trong khi truy vấn dữ liệu từ cơ sở dữ liệu, IEnumerable thực hiện chọn truy vấ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. Do đó làm nhiều việc hơn và trở nên chậm chạp. Trong khi truy vấn dữ liệu từ cơ sở dữ liệu, 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. Do đó làm việc ít hơn và trở nên nhanh chóng.

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.