Interview question
Guard an endpoint against N plus one queries
Uses a test-only DbCommandInterceptor to fail a regression when database command count grows with page size.
TL;DR
Uses a test-only DbCommandInterceptor to fail a regression when database command count grows with page size.
DbCommandInterceptor, N plus one regressions, relational integration tests, query budgets, and non-brittle assertions.
Practice the problem like a real interview: restate, reason, implement, and test.
Add a counting interceptor only to the test DbContext. Seed a page with related rows in an isolated relational database, reset the counter, call the endpoint, and assert no more than two commands. Do not assert exact SQL text.
Next in Production Evidence: Correlated Error
The endpoint stays at one or two commands whether the page contains 5 or 50 parent rows. A lazy-loading regression raises the count toward 51 and fails the test.
I measure commands at the boundary where the regression hurts. A budget assertion is more durable than exact SQL text and still catches per-row queries. I seed enough parent rows to make growth visible.
[Fact]
public async Task Orders_list_has_bounded_database_command_count()
{
var counter = new CommandCountingInterceptor();
await using var factory = await ApiTestFactory.WithIsolatedDatabaseAsync(
configureDb: options => options.AddInterceptors(counter));
await factory.SeedOrdersWithLinesAsync(orderCount: 25);
counter.Reset();
var client = factory.CreateAuthenticatedClient("user-1", "orders.read");
var response = await client.GetAsync("/api/orders?pageSize=25");
response.EnsureSuccessStatusCode();
Assert.InRange(counter.ExecutedCommandCount, 1, 2);
}
This is a targeted relational integration test, not a universal command-count rule. The budget belongs to one important endpoint and should change deliberately when query architecture changes.
Spot a weak answer, missing edge case, or clearer explanation? Send it in.