Entity Framework
Sorting
Querying
Database Management
LINQ

Order by Col1, Col2 using entity framework

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In Entity Framework, ordering by multiple columns is done with OrderBy for the first sort key and ThenBy for each additional key. This maps cleanly to SQL ORDER BY col1, col2. The important detail is that a second OrderBy replaces the first sort, while ThenBy extends it.

Basic Multi-Column Ordering

Suppose you have products and want them sorted by category first and then by price.

csharp
var query = db.Products
    .OrderBy(p => p.Category)
    .ThenBy(p => p.Price);

That translates to the SQL idea of:

ORDER BY Category ASC, Price ASC

Use OrderByDescending and ThenByDescending when needed:

csharp
var query = db.Products
    .OrderBy(p => p.Category)
    .ThenByDescending(p => p.Price);

Now the primary sort is still category ascending, but rows inside each category are sorted by price descending.

Why ThenBy Matters

A common mistake is chaining two OrderBy calls:

csharp
var wrong = db.Products
    .OrderBy(p => p.Category)
    .OrderBy(p => p.Price);

The second OrderBy does not "add" to the first one. It starts a new ordering. In practice, the final result is ordered by price only.

The correct form is:

csharp
var correct = db.Products
    .OrderBy(p => p.Category)
    .ThenBy(p => p.Price);

That distinction is one of the most common LINQ sorting bugs.

Paging Requires Deterministic Ordering

If you use Skip and Take, a stable multi-column order becomes even more important.

csharp
1var page = db.Products
2    .OrderBy(p => p.Category)
3    .ThenBy(p => p.Name)
4    .ThenBy(p => p.Id)
5    .Skip(20)
6    .Take(10);

Including a unique final tie-breaker such as Id helps keep pagination deterministic. Without that, rows with identical sort values can move between pages as data changes.

You can also order by properties from related entities if EF can translate the navigation access.

csharp
var query = db.Orders
    .OrderBy(o => o.Customer.LastName)
    .ThenBy(o => o.CreatedAt);

This is common in reporting screens. Just remember that sort complexity still affects the generated SQL and database execution plan.

Dynamic Ordering Still Needs Care

If users can choose sort columns at runtime, build the expression carefully. A simple branch-based approach is often clearer than trying to invent complex string-driven magic too early.

csharp
1IQueryable<Product> query = db.Products;
2
3query = sortBy switch
4{
5    "price" => query.OrderBy(p => p.Category).ThenBy(p => p.Price),
6    "name"  => query.OrderBy(p => p.Category).ThenBy(p => p.Name),
7    _       => query.OrderBy(p => p.Category).ThenBy(p => p.Id),
8};

This keeps the generated query explicit and easy to debug.

Performance Considerations

Entity Framework can translate multi-column ordering well, but the database still has to execute it. Sorting large result sets can be expensive, especially if the ordered columns are not indexed.

Good practices:

  • index columns frequently used for sorting
  • project only the columns you need
  • combine filtering before ordering when possible
  • use deterministic ordering for paged queries

Example projection:

csharp
1var items = db.Products
2    .Where(p => p.IsActive)
3    .OrderBy(p => p.Category)
4    .ThenBy(p => p.Price)
5    .Select(p => new
6    {
7        p.Id,
8        p.Category,
9        p.Price
10    });

That reduces payload size and keeps the query focused.

Common Pitfalls

  • Using a second OrderBy when ThenBy was intended.
  • Forgetting a stable final tie-breaker when doing pagination.
  • Assuming EF ordering rules differ from normal LINQ ordering semantics.
  • Sorting on large data sets without considering indexes.
  • Building dynamic ordering in a way that obscures the generated SQL.

Summary

  • In Entity Framework, use OrderBy for the first key and ThenBy for additional keys.
  • A second OrderBy replaces the previous order instead of extending it.
  • Use descending variants where required.
  • Add a deterministic final sort key for paging.
  • Think about indexes and query shape because ordering cost is still paid in the database.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.