tags:

views:

123

answers:

3

When we call a query operator on a sequence, a sequence-specific operator gets called.
I mean if i call Where<>() operator on IEnumerable<>, the operator that will be called will be defined in Enumerable class and if it's called on IQueryable<>, the one defined in Queryable class will be called.

Consider the operator Reverse, defined in the Enumerable class.
If i want to call it on Iqueryable<> then I must use the AsEnumerable<>() operator to first convert it into IEnumerable<>.

db.Countries.OrderBy(cntry=>cntry.CountryName).AsEnumerable().Reverse()

But the Reverse operator got to have all records at the same time so that it can reverse them.
In the above code do all the records get loaded in memory first and then the Reverse() operator is reversing it ?

+1  A: 

IQueryable<T> extends IEnumerable<T>, so the AsEnumerable is redundant. However, if you use it, AsEnumerable is not going to greedily load the collection (that would be a very annoying "feature"). Clearly, Reverse will need the whole thing. Mono implements Enumerable.Reverse using a List<T> and a simple iterator-generator that yields in reverse.

I believe the only real purpose of AsEnumerable is to force the use of IEnumerable explicit interface implementations.

Matthew Flaschen
Yes, AsEnumerable will not load everything into memory. In fact, it does nothing except (possibly) change the type.
Matthew Flaschen
But the where operator of Enumerable does not know anything about database access, it needs objects in memory for quering.So Where operator(after calling AsEnumerable) will also load all records from database so that it can filter them out?
Akshay
+3  A: 

AsEnumerable does nothing other than change the compile-time type of the expression.

It's implemented like this:

public static IEnumerable<T> AsEnumerable<T>(this IEnumerable<T> source)
{
    return source;
}

It doesn't even check for nullity!

The only point is to change the compile-time type, to force the rest of the query to be executed with the Enumerable extension methods instead of Queryable. It's like a cast - except a cast would often be inconvenient in the middle of a query, and for anonymous types you wouldn't be able to cast it anyway.

So, it's really about what the "source" of the query does when it's enumerated. Does that source load everything into memory before returning any results, or does it stream them? IIRC, LINQ to SQL will actually load everything into memory - but I could be wrong. Of course Reverse is going to buffer anything anyway, but that doesn't mean it'll use double the memory - in most cases that only means it will buffer references to objects; it doesn't create a new copy of each object.

Jon Skeet
And just to answer the second part of the question, it's the `Reverse` method that is actually loading all of the records.
Dean Harding
So if I do this db.Countries.AsEnumerable().Reverse().Where(c=>c.CountryID=="I"), the query that will be executed will fetch all records from database into memory and then the Reverse and Where operators of Enumerable will work, since they require objects to be in memory for quering and will be very inefficient.Am I right?
Akshay
@Akshay: It would certainly be better to do that in SQL, yes. There's no point in transmitting a load of data which can be discarded. I would suggest using an ordering rather than just reversing the order in which the values come back from the database though.
Jon Skeet
@Jon-> So it does load all records from the database, right ?And which is causing it, AsEnumerable or Reverse ?
Akshay
And even Reverse won't load anything until you ask it for the first element.
Jon Skeet
Actually, Mono's Reverse implementation loads the Enumerable before it returns the iterator-generator. However, there is no real need to do this. I am curious whether MS's behaves the same.
Matthew Flaschen
@Matthew: Really? That sucks. No, the MS implementation is deferred. You can call reverse on `Enumerable.Range(0, int.MaxValue)` so long as you don't try to use the result :) I'd argue this is a Mono bug if you're right, as the documentation states: "The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic."
Jon Skeet
@Jon, yeah, I've filed [a bug](https://bugzilla.novell.com/show_bug.cgi?id=608195) with a [simple patch](https://bugzilla.novell.com/attachment.cgi?id=364031). I'd appreciate it if people look it over.
Matthew Flaschen
A: 

Why don't you use the OrderByDescending method?

Devart