# LINQ — C#/.NET

Source: https://www.skillbyai.com/en/dotnet/l-linq

> Query in-memory data with LINQ and understand deferred execution.

## Queries as composable methods

**LINQ** (Language Integrated Query) adds query operators to any `IEnumerable<T>`: `Where` (filter), `Select` (project), `OrderBy`/`ThenBy`, `GroupBy`, `Join`, `Any`/`All`, `Count`, `Sum`, `First`/`FirstOrDefault`, `Distinct`, `Take`/`Skip`, `Chunk` and many more. You can write the same query in **method syntax** (`orders.Where(o => o.Total > 500)`) or **query syntax** (`from o in orders where o.Total > 500 select o`). Most operators use **deferred execution**: building the query does nothing; it runs when you enumerate it (with `foreach`, `ToList()`, `Count()` and so on), and it runs **again** each time you enumerate. Call `ToList()` or `ToArray()` when you want a snapshot. LINQ to Objects works on in-memory data with delegates; **`IQueryable<T>`** providers, such as Entity Framework Core, translate the same operators into SQL.

## Grouping and summarising orders

Nothing executes until `ToList()` is called.

```cs
var orders = new List<Order>
{
    new("o1", "Pune", 1200m), new("o2", "Delhi", 300m),
    new("o3", "Pune", 800m),  new("o4", "Delhi", 2500m),
};

var byCity = orders
    .Where(o => o.Total >= 500m)
    .GroupBy(o => o.City)
    .Select(g => new { City = g.Key, Count = g.Count(), Revenue = g.Sum(o => o.Total) })
    .OrderByDescending(x => x.Revenue)
    .ToList();                      // executes here

foreach (var row in byCity)
    Console.WriteLine($"{row.City}: {row.Count} orders, {row.Revenue:C}");

bool anyBig = orders.Any(o => o.Total > 2000m);

record Order(string Id, string City, decimal Total);
```

## First versus FirstOrDefault versus Single

`First` throws if nothing matches; `FirstOrDefault` returns `null`/default; `Single` throws if there is not exactly one match. Choose deliberately: `Single` documents that duplicates would be a bug.

**Quiz:** When does a LINQ query like `orders.Where(o => o.Total > 500)` actually run?

- [ ] When the line is executed
- [ ] At compile time
- [ ] Only when the garbage collector runs
- [x] When it is enumerated, for example by foreach or ToList()

*Answer:* When it is enumerated, for example by foreach or ToList(). Most LINQ operators are deferred and execute on enumeration.
