17

Example code:

List<Student> Students = new List<Student>()   
{   
    new Student(101, "Hugo", "Garcia", new List<int>() { 91, 88, 76, 93 }),  
    new Student(102, "Rick", "Adams", new List<int>() { 70, 73, 66, 90 }),  
    new Student(103, "Michael", "Tucker", new List<int>() { 73, 80, 75, 88 }),  
    new Student(104, "Fadi", "Fakhouri", new List<int>() { 82, 75, 66, 84 }),  
    new Student(105, "Peter", "Barrows", new List<int>() { 67, 78, 70, 82 })  
};

var query = from student in Students
            where student.Marks.AsQueryable().All(m => m > 70)
            select student;

foreach (Student student in query)
{
    Console.WriteLine("{0} {1}<br />", student.FirstName, student.LastName);
}

But if I change the query to

var query = from student in Students
            where student.Marks.All(m => m > 70)
            select student;

This also works and produces the same result, so what's the difference?

Tilak
  • 30,108
  • 19
  • 83
  • 131
Cheung
  • 15,293
  • 19
  • 63
  • 93
  • A similar question on [`AsEnumerable`](http://stackoverflow.com/questions/3389855/am-i-misunderstanding-linq-to-sql-asenumerable) – nawfal Sep 29 '13 at 06:31

3 Answers3

10

IQueryable is required/recommended for objects coming from remote source (like from database).

For in memory collections it is of no use.

AsQueryable is used when expression tree is to be constructed.

I can think of scenario where it is best fit. In your example let say you require some information from database based on student ID.

Now student is in memory collection. You need to fire database query based on student ID.

  var studentList = Students.Select(s => s.Id).AsQueryAble().Select(i => remoteDBProvider.GetInfo(i));

Any further operation on the studentList will be invoked from IQueryAble interface ( query expression), and will fetch only those records from data source, which should be returned as final query result (as long as data source, return value of remoteDBProvider.GetInfo in the example, supports QueryProvider).

Aage
  • 5,932
  • 2
  • 32
  • 57
Tilak
  • 30,108
  • 19
  • 83
  • 131
  • 6
    @BorisB. That is simply not true. [Enumerable.Select](http://msdn.microsoft.com/en-us/library/bb548891.aspx) uses deferred execution as well. The difference is that Queryable accepts the lambda as an expression. This allows a query provider to inspect the expression and translate it into something (potentially) more efficient, e.g. a SQL query. Any projections or filtering will take place in the database instead of in the application, taking advantage of the database's native code. But for in-memory collections it doesn't make a difference. – Niels van der Rest Jul 29 '13 at 07:51
  • @NielsvanderRest: You are right, comment deleted since it's misleading (or simply untrue). Nevertheless, `AsQueryable` still has it's uses even for memory collections, since it's `Select` extension method accepts an `Expression`, which enables you to analyze or modify it. One scenario I can think of is using the in-memory collection wrapped in a `IQueryable` as a way for a persistence-unaware layer to send a query as an AST to a persistence-aware layer. – Boris B. Jul 29 '13 at 11:56
3

In the case of your List<Student>, it doesn't make any difference, as the returned IQueryable<T> will use the same methods for querying as if you hadn't used AsQueryable() at all.

Some Methods expect an IQueryable<T> parameter. I think the AsQueryable() extension method is mostly useful for those scenarios, when you need to pass an IQueryable<T> but only have an IEnumerable<T>.

MSDN says about AsQueryable:

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

So that means in your case (List<T> does not implement IQueryable<T>), you really don't need AsQueryable.

Botz3000
  • 39,020
  • 8
  • 103
  • 127
2

It has to do how the expression tree is build. Look at this:

AsQueryable is a method that allow the query to be converted to an instance of IQueryable. When you use AsQueryable operator on an existing query and apply further transformations such as applying a filter or specifying a sort order, those lambda statements are converted to Expression trees. Depending on the provider you are using, expression trees will be converted into the domain specific syntax and than executed. In the case of Linq to SQL provider, the expression tree would be converted to SQL and executed on SQL server. However if you use AsQueryable operator on a query that does not implement IQueryable and only implements IEnumerable, than any transformations that you apply on the query would automatically fall back on IEnumerable specification. What this means is by tagging a query with AsQueryable you get benefits of both Linq to SQL and Linq to object implementation. If your existing query happens to implement IQueryable, the query is converted to SQL by the Linq to SQL provider, otherwise the query is executed in memory in the form IL code.

Reference here

Arion
  • 31,011
  • 10
  • 70
  • 88