Interview question
Project an order list directly into a DTO
Builds a read-only EF Core projection with aggregates, stable ordering, and bounded results instead of loading an entity graph.
TL;DR
Builds a read-only EF Core projection with aggregates, stable ordering, and bounded results instead of loading an entity graph.
DTO projection, aggregate translation, no-tracking reads, deterministic ordering, pagination, and null-safe totals.
Practice the problem like a real interview: restate, reason, implement, and test.
Entities are Order, Customer, and OrderLine. Return the newest paid orders as OrderListItem(OrderId, CustomerName, CreatedAtUtc, LineCount, ItemQuantity, Total). The endpoint does not modify entities and accepts a validated page size no greater than 100.
Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Practice the next layer of the same subject.
An order with two lines containing quantities 2 and 3 returns LineCount = 2, ItemQuantity = 5, and the sum of quantity multiplied by unit price. No entity navigation collections are materialized.
CreatedAtUtc and then Id descending.I keep the full query as IQueryable until the final ToListAsync. The projection lets EF translate navigation access and aggregates into SQL. A nullable decimal cast makes an empty sum safe, although a real order should normally have at least one line. AsNoTracking expresses that this path does not need change tracking.
public static Task<List<OrderListItem>> LoadPaidOrdersAsync(
AppDbContext db,
int pageSize,
CancellationToken cancellationToken)
{
pageSize = Math.Clamp(pageSize, 1, 100);
return db.Orders
.AsNoTracking()
.Where(order => order.Status == OrderStatus.Paid)
.OrderByDescending(order => order.CreatedAtUtc)
.ThenByDescending(order => order.Id)
.Select(order => new OrderListItem(
order.Id,
order.Customer.DisplayName,
order.CreatedAtUtc,
order.Lines.Count(),
order.Lines.Sum(line => line.Quantity),
order.Lines.Sum(line =>
(decimal?)(line.Quantity * line.UnitPrice)) ?? 0m))
.Take(pageSize)
.ToListAsync(cancellationToken);
}
EF Core emits one bounded SQL query with correlated aggregates or equivalent joins, depending on the provider. The database returns DTO-shaped scalar data rather than full orders, customers, and lines. The order and filter columns should be supported by the production query's index strategy.
ToQueryString() and verify only required columns are selected.ToListAsync.Include when the endpoint needs only scalar DTO fields.ToList before Select and projecting in memory.Spot a weak answer, missing edge case, or clearer explanation? Send it in.