Interview question
Load a tracked aggregate with a split query
Uses `AsSplitQuery` deliberately for a tracked aggregate with multiple collections and explains its consistency boundary.
TL;DR
Uses AsSplitQuery deliberately for a tracked aggregate with multiple collections and explains its consistency boundary.
Include shape, split versus single query, tracking, row multiplication, transaction consistency, and aggregate boundaries.
Practice the problem like a real interview: restate, reason, implement, and test.
An order command needs the tracked Order, all Lines, and all Payments before applying a domain operation. Two sibling collection includes create a large cross product in one SQL query. Implement a deliberate split-query load.
An order with 20 lines and 10 payments should not produce 200 joined result rows just to reconstruct one aggregate.
I keep the aggregate load explicit and tracked, but split the sibling collections into separate SQL commands to avoid cartesian multiplication. Split queries trade one huge result for several commands. If concurrent changes between those commands would violate the operation's assumptions, I would use an appropriate transaction or redesign the command around narrower data.
public static async Task<Order> LoadOrderForCommandAsync(
AppDbContext db,
Guid orderId,
CancellationToken cancellationToken)
{
return await db.Orders
.Include(order => order.Lines)
.Include(order => order.Payments)
.AsSplitQuery()
.SingleAsync(
order => order.Id == orderId,
cancellationToken);
}
The provider issues one query for the order and additional queries for included collections. Total transferred rows are usually far lower than a cross product, but round trips increase. Measure both shapes with realistic collection sizes and confirm the command truly needs the full tracked aggregate.
SingleAsync.AsNoTracking to an aggregate that will be modified.Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Practice the next layer of the same subject.