LINQ
Max()
C#
Query
Data Retrieval

LINQ Using Max to select a single row

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Using Max in LINQ often causes confusion because Max returns a scalar value, not the full row that contains that value. If you need the actual record with the highest score, latest timestamp, or biggest amount, combine sorting or grouping with a selection step. The right pattern depends on whether you need one global row or one row per group.

Why Max Alone Is Not Enough

Consider this class:

csharp
1public class Sale {
2    public int Id { get; set; }
3    public string Region { get; set; } = "";
4    public decimal Amount { get; set; }
5    public DateTime CreatedAt { get; set; }
6}

This gives only the largest amount:

csharp
decimal maxAmount = sales.Max(x => x.Amount);

You still do not know which row produced it, especially if multiple rows share the same value.

Select One Global Row with Ordering

For one best row in the whole sequence, order descending and take first.

csharp
1Sale topSale = sales
2    .OrderByDescending(x => x.Amount)
3    .ThenByDescending(x => x.CreatedAt)
4    .First();
5
6Console.WriteLine($"Top sale id={topSale.Id}, amount={topSale.Amount}");

The secondary sort with ThenByDescending makes tie-breaking deterministic.

If the sequence may be empty, use FirstOrDefault and handle null.

Select One Row Per Group

When you need one row per region, group first and pick the top item from each group.

csharp
1var topPerRegion = sales
2    .GroupBy(x => x.Region)
3    .Select(g => g
4        .OrderByDescending(x => x.Amount)
5        .ThenByDescending(x => x.CreatedAt)
6        .First())
7    .ToList();
8
9foreach (var s in topPerRegion) {
10    Console.WriteLine($"{s.Region}: {s.Amount}");
11}

This pattern is common in dashboards and ranking reports.

EF Core Translation Considerations

In LINQ-to-Objects, all patterns above run in memory. In EF Core, translation to SQL can vary by provider and version. A safe approach for large datasets is projecting only needed columns and ensuring indexes support your sorting keys.

csharp
1var query = dbContext.Sales
2    .OrderByDescending(x => x.Amount)
3    .ThenByDescending(x => x.CreatedAt)
4    .Select(x => new { x.Id, x.Amount, x.Region })
5    .FirstOrDefault();

Inspect generated SQL during performance tuning. If translation becomes complex for group-wise top selection, a database view or window-function query may be clearer.

Handle Ties Explicitly

Business rules often require tie handling. You may need all rows with the max value instead of one arbitrary row.

csharp
decimal maxAmount = sales.Max(x => x.Amount);
var allMaxRows = sales.Where(x => x.Amount == maxAmount).ToList();

Define tie policy early so reports remain consistent.

Modern Alternative with MaxBy

In newer .NET versions, MaxBy can return the row directly and reduce boilerplate for simple cases.

csharp
1var top = sales.MaxBy(x => x.Amount);
2if (top is not null)
3{
4    Console.WriteLine($"Top sale {top.Id} amount {top.Amount}");
5}

You still need explicit tie policy. MaxBy returns one matching row, not all ties. If the business rule says keep every max row, compute max value first and filter by equality.

For older targets without MaxBy, keep using OrderByDescending().FirstOrDefault() or implement a small helper extension. Prefer readability over clever one-liners, especially when queries evolve with additional business filters.

Common Pitfalls

A major pitfall is calling Max and then searching again with First, which can perform two passes and hide tie behavior. Prefer one query when possible.

Another issue is forgetting empty-sequence handling. First and Max throw on empty sets unless you protect them.

For EF queries, client-side evaluation can accidentally pull large data into memory. Keep expensive filtering and ordering in SQL when datasets are large.

Finally, use deterministic secondary sorting whenever selecting a single row from equal max values.

Summary

  • Max returns only a value, not the row.
  • Use ordered selection for one global row.
  • Use group plus ordered selection for one row per category.
  • Define tie behavior explicitly for predictable results.
  • Validate SQL translation and performance when running against databases.

Course illustration
Course illustration

All Rights Reserved.