131

Is the purpose of AsQueryable() just so you can pass around an IEnumerable to methods that might expect IQueryable, or is there a useful reason to represent IEnumerable as IQueryable? For example, is it supposed to be for cases like this:

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

Or does it actually make it do something different:

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

Do the IQueryable versions of these extension methods just build up an Expression that ends up doing the same thing once its executed? My main question is, whats a real use case for using AsQueryable?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Ocelot20
  • 10,510
  • 11
  • 55
  • 96

5 Answers5

84

There are a few main uses.

  1. As mentioned in other answers, you can use it to mock a queryable data source using an in-memory data source so that you can more easily test methods that will eventually be used on a non-enumerable based IQueryable.

  2. You can write helper methods for manipulating collections that can apply to either in-memory sequences or external data sources. If you write your help methods to use IQueryable entirely you can just use AsQueryable on all enumerables to use them. This allows you to avoid writing two separate versions of very generalized helper methods.

  3. It allows you to change the compile time type of a queryable to be an IQueryable, rather than some more derived type. In effect; you'd use it on an IQueryable at the same times that you'd use AsEnumerable on an IEnumerable. You might have an object that implements IQueryable but that also has an instance Select method. If that were the case, and you wanted to use the LINQ Select method, you'd need to change the compile time type of the object to IQueryable. You could just cast it, but by having an AsQueryable method you can take advantage of type inference. This is simply more convenient if the generic argument list is complex, and it is actually necessary if any of the generic arguments are anonymous types.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • Thanks for the revival. Marking this as the answer since it's the most complete. – Ocelot20 Dec 04 '13 at 16:28
  • 5
    Given that `IQueryable` derives from `IEnumerable` can you please explain what you mean by "non-enumerable based IQueryable"? – Dai Sep 25 '16 at 16:50
  • 2
    @Dai It's referring to an `IQueryable` that is more than just a wrapped `IEnumerable`, and that actually leverages the additional capabilities of an `IQueryable`. – Servy Sep 26 '16 at 03:03
  • #1 is exactly what I was seeking it for. Thank you for verifying. – one.beat.consumer Oct 27 '16 at 20:14
15

The most valid case I have for AsQueryable is unit testing. Say I have the following somewhat contrived example

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

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


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

and I want to write a unit test to make sure the controller passes back the results returned from the repository. It'd look something like this:

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

where really, all the AsQueryable() method allows me to do is satisfy the compiler when setting up a mock.

I'd be interested where this is used in application code though.

Jim Aho
  • 9,932
  • 15
  • 56
  • 87
chris
  • 151
  • 1
  • 3
14

As sanjuro noted, the purpose of AsQueryable() is explained in Using AsQueryable With Linq To Objects And Linq To SQL. In particular, the article states,

This offers an excellent benefits in real word scenarios where you have certain methods on an entity that return an IQueryable of T and some methods return List. But then you have business rule filter that needs to be applied on all the collection regardless if the collection is returned as IQueryable of T or IEnumerable of T. From a performance stand point, you really want to leverage executing the business filter on the database if the collection implements IQueryable otherwise fall back to apply the business filter in memory using Linq to object implementation of delegates.

Scott
  • 4,458
  • 1
  • 19
  • 27
10

The purpose of AsQueryable() is greatly explained in this article Using AsQueryable With Linq To Objects And Linq To SQL

From Remarks section of MSDN Queryable.AsQueryable Method:

If the type of source implements IQueryable, AsQueryable(IEnumerable) returns it directly. Otherwise, it returns an IQueryable that executes queries by calling the equivalent query operator methods in Enumerable instead of those in Queryable.

Thats is exactly what is mentioned and used in above article. In your example, it depends on what is orderRepo.GetAll returning, IEnumerable or IQueryable(Linq to Sql). If it returns IQueryable, the Count() method will be executed on database otherwise it will be executed in memory. Look carefully at example in referenced article.

sanjuro
  • 1,611
  • 1
  • 21
  • 29
4

Interface IQueryable quoting documentation:

The IQueryable interface is intended for implementation by query providers.

So for someone that intends to make its datastracture queryable in .NET, that datastructure that not necessary can be enumerated or have valid enumerator.

IEnumerator is an interface for iterating and processing stream of data instead.

Tigran
  • 61,654
  • 8
  • 86
  • 123
  • Would you mind rephrasing this: " that datastructure that not necessary can be enumerated or have valid enumerator". I understand the difference between `IQueryable` and `IEnumerable`, but I don't understand the use case for the `AsQueryable` extension method. I am getting a bit tripped up on that sentence though, which I suspect might have the answer I'm looking for (based on the upvotes). – Ocelot20 Jun 28 '13 at 14:37
  • @Ocelot20: that mean hat datastructure presented by provider that implements IQueryable *may* not provide an enumeration cappability. It's up to provider. Quoting doc: "Queries that do not return enumerable results are executed when the Execute method is called." – Tigran Jun 28 '13 at 14:47
  • Maybe I'm missing something obvious, but I still don't see the answer to "why would I need to use `AsQueryable()`?" If I'm *starting* with an IEnumerable (something already capable of providing an enumeration capability), why would I need to convert to `IQueryable` using the extension method `AsQueryable()`? Maybe a small code example to illustrate where this would come in handy? I seem to be missing something in your explanation. Thanks for your time. – Ocelot20 Jun 28 '13 at 16:20
  • @Ocelot20: to really show the difference i need to write query provider. You know that we have `linq to sql`, `linq to xml` and so.. if you want to write `linq` driver that targets *your* data strucutres (`linq to your data`), so users of your api will have a possibility to run `linq` query against *your* data structures, you have to choose `IQueryable` – Tigran Jun 28 '13 at 17:22
  • 2
    You seem to be explaining the difference between `IQueryable` and `IEnumerable`. I know the difference, and that's not what I'm asking for. I'm asking why someone would want to take something that implements `IEnumerable`, and convert it into an `IQueryable` using the `AsQueryable` extension method. Is that what you're answering? I still can't tell.. – Ocelot20 Jun 28 '13 at 17:28
  • @Ocelot20: there is no much sence, imo, from IEnumerable jump to IQuerable. Vice versa, instead, yes. – Tigran Jun 28 '13 at 17:53