2

I have an IEnumerable variable named "query" which represents an entity framework query. If I do the following, will it enumerate the query more than once? My confusion is in "result" being an IEnumerable and not a List.

IEnumerable<T> result = query.ToList();
bool test = result.Any();

as apposed to this:

// Using List to only enumerate the query once
List<T> result = query.ToList();
bool test = result.Any();

Also, I know this is silly, but would it enumerate twice if I do the following, or would it somehow know that "query" was already enumerated even though the result of the enumeration is not being used?

List<T> result = query.ToList();
bool test = query.Any();

Thanks!

Bumper
  • 367
  • 6
  • 17

3 Answers3

3

Once you're calling ToList or ToArray you will create an in-memory collection. From then on you're not dealing with the database anymore.

So even if you declare it as IEnumerable<T> it actually remains a List<T> after query.ToList().

Also, all related LINQ extension methods will check if the sequence can be casted to a collection type. You can see that for example in Enumerable.Count the Count property wil be used if possible:

public static int Count<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        checked {
            while (e.MoveNext()) count++;
        }
    }
    return count;
}

According to your last question, if it makes a difference wether or not you use the list or again the query in this code snippet:

List<T> result = query.ToList();
bool test = query.Any();

Yes, in this case you are not using the list in memory but the query which will then ask the database again even if .Any is not as expensive as .ToList.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

No the enumeration occour only in ToList().

http://msdn.microsoft.com/it-it/library/bb342261(v=vs.110).aspx

abrfra
  • 634
  • 2
  • 6
  • 24
1

When you call ToList on your query it will be transformed into a list. The query will be evaluated right then, the items will be pulled out, and the list will be populated. From then on that List has no knowledge of the original query. No amount of manipulation of that list can in any way affect or evaluate that query, as it knows nothing about it.

It doesn't matter what you call that List, or what type of variable you stick it in, the list itself simply doesn't know anything about the IQueryable anymore. Iterating the variable holding the list multiple times will simply iterate that list multiple times.

In just the same way that the list doesn't know a thing about the query, the query doesn't know a thing about the list. It doesn't remember that it's items were put into a list and continue to return those items. (You can actually write query objects like this, in theory. It's called memoization, for the query to cache it's results when iterated and continue to provide objects from that cache when iterated later. EF doesn't memoize its queries by default, nor does it provide a tool for memoization by default, although 3rd party tools provide such extensions.) This means that the 3rd code snippet that you have will actually execute two separate database queries, not just one.

Servy
  • 202,030
  • 26
  • 332
  • 449