Mục đích của AsQueryable () là gì?


107

Mục đích AsQueryable()là để bạn có thể chuyển một IEnumerabletới các phương thức mà bạn có thể mong đợi IQueryable, hay có lý do hữu ích nào để thể hiện IEnumerablenhư IQueryablevậy không? Ví dụ, nó phải dành cho những trường hợp như thế này:

IEnumerable<Order> orders = orderRepo.GetAll();

// I don't want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());

public static int CountOrders(IQueryable<Order> ordersQuery)
{
    return ordersQuery.Count();
}

Hay nó thực sự khiến nó làm điều gì đó khác biệt:

IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();

IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);

// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();

Có phải các IQueryablephiên bản của các phương thức mở rộng này chỉ xây dựng một Biểu thức kết thúc hoạt động tương tự khi nó được thực thi không? Câu hỏi chính của tôi là, trường hợp sử dụng thực sự để sử dụng là AsQueryablegì?

Câu trả lời:


65

Có một số cách sử dụng chính.

  1. Như đã đề cập trong các câu trả lời khác, bạn có thể sử dụng nó để mô phỏng nguồn dữ liệu có thể truy vấn bằng cách sử dụng nguồn dữ liệu trong bộ nhớ để bạn có thể dễ dàng kiểm tra các phương pháp cuối cùng sẽ được sử dụng dựa trên không thể liệt kê IQueryable.

  2. Bạn có thể viết các phương thức trợ giúp để thao tác các bộ sưu tập có thể áp dụng cho các trình tự trong bộ nhớ hoặc các nguồn dữ liệu bên ngoài. Nếu bạn viết các phương thức trợ giúp của mình để sử dụng IQueryablehoàn toàn, bạn chỉ có thể sử dụng AsQueryabletrên tất cả các bảng liệt kê để sử dụng chúng. Điều này cho phép bạn tránh viết hai phiên bản riêng biệt của các phương thức trợ giúp rất tổng quát.

  3. Nó cho phép bạn thay đổi kiểu thời gian biên dịch của một truy vấn thành một kiểu IQueryablethay vì một số kiểu dẫn xuất khác. Có hiệu lực; bạn sẽ sử dụng nó vào IQueryablecùng một thời điểm mà bạn sẽ sử dụng AsEnumerabletrên IEnumerable. Bạn có thể có một đối tượng thực hiện IQueryablenhưng đối tượng đó cũng có một Selectphương thức thể hiện. Nếu đúng như vậy và bạn muốn sử dụng Selectphương thức LINQ , bạn cần thay đổi kiểu thời gian biên dịch của đối tượng thành IQueryable. Bạn chỉ có thể truyền nó, nhưng bằng cách có một AsQueryablephương pháp, bạn có thể tận dụng lợi thế của suy luận kiểu. Điều này chỉ đơn giản là thuận tiện hơn nếu danh sách đối số chung phức tạp và nó thực sự cần thiết nếu bất kỳ đối số chung nào là loại ẩn danh.


Cảm ơn vì sự hồi sinh. Đánh dấu đây là câu trả lời vì nó là câu trả lời đầy đủ nhất.
Ocelot

5
Với IQueryable<T>nguồn gốc từ đó, IEnumerable<T>bạn có thể vui lòng giải thích ý bạn của "IQueryable dựa trên không liệt kê được" không?
Đại

2
@Dai Nó đề cập đến một IQueryablekhông chỉ là một cái bọc IEnumerable, và nó thực sự thúc đẩy các khả năng bổ sung của một IQueryable.
Servy

# 1 chính xác là những gì tôi đang tìm kiếm nó. Cảm ơn bạn đã xác minh.
one.beat.consumer

12

Trường hợp hợp lệ nhất mà tôi có cho AsQueryable là thử nghiệm đơn vị. Giả sử tôi có một ví dụ hơi giả tạo sau đây

public interface IWidgetRepository
{
   IQueryable<Widget> Retrieve();
} 

public class WidgetController
{
   public IWidgetRepository WidgetRepository {get; set;}


   public IQueryable<Widget> Get()
   {
      return WidgetRepository.Retrieve();
   }
}

và tôi muốn viết một bài kiểm tra đơn vị để đảm bảo bộ điều khiển chuyển lại kết quả trả về từ kho lưu trữ. Nó trông giống như thế này:

[TestMethod]
public void VerifyRepositoryOutputIsReturned()
{    
    var widget1 = new Widget();
    var widget2 = new Widget();
    var listOfWidgets = new List<Widget>() {widget1, widget2};
    var widgetRepository = new Mock<IWidgetRepository>();
    widgetRepository.Setup(r => r.Retrieve())
      .Returns(listOfWidgets.AsQueryable());
    var controller = new WidgetController();
    controller.WidgetRepository = widgetRepository.Object;

    var results = controller.Get();

    Assert.AreEqual(2, results.Count());
    Assert.IsTrue(results.Contains(widget1));
    Assert.IsTrue(results.Contains(widget2));
}

thực sự, tất cả những gì mà phương thức AsQueryable () cho phép tôi làm là đáp ứng trình biên dịch khi thiết lập một mô hình.

Tuy nhiên, tôi muốn quan tâm đến nơi điều này được sử dụng trong mã ứng dụng.


11

Như sanjuro đã lưu ý, mục đích của AsQueryable () được giải thích trong Sử dụng AsQueryable Với Linq To Objects và Linq To SQL . Đặc biệt, bài báo viết rằng,

Điều này mang lại một lợi ích tuyệt vời trong các kịch bản từ thực tế, nơi bạn có một số phương thức nhất định trên một thực thể trả về IQueryable T và một số phương thức trả về Danh sách. Nhưng sau đó, bạn có bộ lọc quy tắc nghiệp vụ cần được áp dụng trên tất cả bộ sưu tập bất kể bộ sưu tập được trả về là IQueryable của T hay IEnumerable của T. Từ quan điểm hiệu suất, bạn thực sự muốn tận dụng việc thực thi bộ lọc nghiệp vụ trên cơ sở dữ liệu nếu bộ sưu tập triển khai IQueryable nếu không thì quay lại áp dụng bộ lọc nghiệp vụ trong bộ nhớ bằng cách sử dụng Linq để triển khai đối tượng của các đại biểu.


6

Mục đích của AsQueryable () được giải thích rất nhiều trong bài viết này Sử dụng AsQueryable Với Linq Để Đối tượng và Linq Với SQL

Từ phần Ghi chú của Phương thức MSDN Queryable.AsQueryable:

Nếu loại nguồn triển khai IQueryable, AsQueryable (IEnumerable) trả về nó trực tiếp. Nếu không, nó trả về một IQueryable thực thi các truy vấn bằng cách gọi các phương thức toán tử truy vấn tương đương trong Enumerable thay vì các phương thức trong Queryable.

Đó là chính xác những gì được đề cập và sử dụng trong bài viết trên. Trong ví dụ của bạn, nó phụ thuộc vào trả về orderRepo.GetAll, IEnumerable hoặc IQueryable (Linq to Sql). Nếu nó trả về IQueryable, phương thức Count () sẽ được thực thi trên cơ sở dữ liệu nếu không nó sẽ được thực thi trong bộ nhớ. Xem kỹ ví dụ trong bài viết tham khảo.


3

IQueryableTài liệu trích dẫn giao diện :

Giao diện IQueryable được dành cho các nhà cung cấp truy vấn triển khai.

Vì vậy, đối với ai đó có ý định làm cho cấu trúc dữ liệu của nó có thể truy vấn trong .NET, cấu trúc dữ liệu đó không cần thiết có thể được liệt kê hoặc có trình kê khai hợp lệ .

IEnumeratorlà một giao diện để lặp lại và xử lý luồng dữ liệu thay thế.


Bạn có phiền khi diễn đạt lại điều này không: "cấu trúc dữ liệu đó không cần thiết có thể được liệt kê hoặc có bộ điều tra hợp lệ". Tôi hiểu sự khác biệt giữa IQueryableIEnumerable, nhưng tôi không hiểu trường hợp sử dụng cho AsQueryablephương thức mở rộng. Mặc dù vậy, tôi hơi vấp phải câu đó, mà tôi nghi ngờ có thể có câu trả lời mà tôi đang tìm kiếm (dựa trên số phiếu ủng hộ).
Ocelot 20

@ Ocelot20: có nghĩa là cơ cấu dữ liệu mũ được trình bày bởi nhà cung cấp triển khai IQueryable có thể không cung cấp khả năng liệt kê. Đó là vào nhà cung cấp. Trích dẫn doc: "Các truy vấn không trả về kết quả có thể liệt kê được thực thi khi phương thức Execute được gọi."
Tigran

Có thể tôi đang thiếu một cái gì đó rõ ràng, nhưng tôi vẫn không thấy câu trả lời cho "tại sao tôi cần sử dụng AsQueryable()?" Nếu tôi đang bắt đầu với IEnumerable (một thứ đã có khả năng cung cấp khả năng liệt kê), tại sao tôi cần chuyển đổi sang IQueryablesử dụng phương thức mở rộng AsQueryable()? Có thể một ví dụ mã nhỏ để minh họa điều này sẽ có ích ở đâu? Tôi dường như thiếu một cái gì đó trong lời giải thích của bạn. Cảm ơn vì đã dành thời gian cho tôi.
Ocelot 20

@ Ocelot20: để thực sự cho thấy sự khác biệt, tôi cần viết nhà cung cấp truy vấn. Bạn biết rằng chúng tôi có linq to sql, linq to xmlvà vì vậy .. nếu bạn muốn viết linqtrình điều khiển nhắm mục tiêu strucutres dữ liệu của bạn ( linq to your data), vì vậy người dùng api của bạn sẽ có khả năng chạylinq truy vấn chống lại cấu trúc dữ liệu của bạn , bạn phải chọnIQueryable
Tigran

2
Bạn dường như đang giải thích sự khác biệt giữa IQueryableIEnumerable. Tôi biết sự khác biệt, và đó không phải là điều tôi yêu cầu. Tôi đang hỏi tại sao ai đó lại muốn lấy một thứ gì đó thực hiện IEnumerablevà chuyển đổi nó thànhIQueryableAsQueryable phương thức mở rộng bằng cách sử dụng . Đó là những gì bạn đang trả lời? Tôi vẫn không thể nói ..
Ocelot 20
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.