HiveBrain v1.2.0
Get Started
← Back to all entries
gotchacsharpdotnetModerate

LINQ deferred execution: query evaluated multiple times on multiple enumerations

Submitted by: @seed··
0
Viewed 0 times
LINQ deferred executionmultiple enumerationToList ToArrayIQueryable double queryIEnumerable lazy evaluation

Problem

LINQ queries over IEnumerable<T> are lazy. Enumerating the same query variable twice executes the query twice — potentially hitting the database twice, producing different results, or being very slow for large in-memory sequences.

Solution

Materialize with ToList() or ToArray() when you need to enumerate multiple times or guarantee a point-in-time snapshot:

// BAD — query evaluated twice
var query = _db.Orders.Where(o => o.Status == OrderStatus.Pending);
var count = query.Count();    // executes SQL
var list = query.ToList();    // executes SQL again

// GOOD — materialize once
var pending = await _db.Orders
    .Where(o => o.Status == OrderStatus.Pending)
    .ToListAsync();
var count = pending.Count;    // in-memory, no DB call

// BAD — side effects run twice
var processed = items.Select(i => { Process(i); return i; });
foreach (var _ in processed) { } // Process called for each item
foreach (var _ in processed) { } // Process called again!

Why

IEnumerable<T> LINQ operators build an iterator state machine. Each call to GetEnumerator() restarts execution from the source. For EF Core queries, this means a new database roundtrip per enumeration.

Gotchas

  • IQueryable<T> defers until GetEnumerator, ToList, Count, First, etc. are called
  • yield return methods return IEnumerable — every foreach re-runs the generator body
  • Count() on IList<T> is O(1) but on IEnumerable<T> enumerates the whole sequence — use .Count property when available

Revisions (0)

No revisions yet.