Whetstone.
LINQ vs JS array methodsThe method mapping and laziness
Module 6 · Lesson 113 min

The method mapping and laziness

LINQ is the same shape as JS array methods with different names. Once you learn the dictionary you can read most of it on sight.

LINQ, mapped from JS array methods
Select.map() — project each element
Where.filter() — keep elements matching a predicate
Any.some() — is there at least one match
All.every() — do all match
First.find() but throws if none; use FirstOrDefault for find's undefined
OrderBy.sort() by a key, ascending (OrderByDescending for desc)
ToList[...iterable] — force it to a concrete List now

The trap is laziness. A JS .map().filter() runs immediately and gives you an array. A LINQ chain over IEnumerable<T> is a query description: nothing runs until you materialize it with ToList(), FirstOrDefault(), Any(), or a foreach. That deferral is what lets LINQ over a database translate the whole chain into SQL instead of running it in C#.

That’s also where the most common performance slop comes from. If you materialize too early, you pull the whole table into memory and filter in C#. Fusion anti-pattern #7: push the filter into the query. Where before ToListAsync, so the database does the work with its indexes.

Anti-pattern #7: filter in the query, not after
// Wrong: loads every row, then filters in memory (O(N) table scan).
var all = await _db.FlightDisruptionCostCalcs.ToListAsync();
var mine = all.Where(x => x.FlightNumber == flightNumber);

// Right: the WHERE becomes SQL; the DB returns only matching rows.
var mine = await _db.FlightDisruptionCostCalcs
    .Where(x => x.FlightNumber == flightNumber)
    .ToListAsync();
Practice

Try it yourself

Do

Read a real query-store LINQ chain

Confirm the filter-then-materialize order in shipping code.

  • Open persistence/DisruptionDecisions/DecisionQueryStore.cs
  • Find GetDecidedFlightIdentities and read the chain: .AsNoTracking().Where(...).Select(...).ToListAsync()
  • Note the Where and Select come BEFORE ToListAsync, so they translate to SQL
  • Note .AsNoTracking() at the front (Module 9 explains why every read query has it)
Done whenYou traced a LINQ chain where filtering and projection happen before materialization, so the database does the work.
Quiz

When does the query run

You write _db.Flights.Where(x => x.Active) and assign it to a variable. When does the database get hit?

  1. AImmediately, at the moment the Where call is first evaluated
  2. BNever, Where isn't supported
  3. CWhen you materialize it: ToListAsync, FirstOrDefaultAsync, Any, or foreach
  4. DWhen the variable goes out of scope
Show answer

Correct answer: C — When you materialize it: ToListAsync, FirstOrDefaultAsync, Any, or foreach

LINQ over a DbSet is deferred. The chain is a query description; it executes as SQL only when you materialize it with ToListAsync/FirstOrDefaultAsync/Any/foreach.

Sign in to track your progress →