Catch repeated EF Core queries in tests
QueryGuard counts database queries, groups repeated SQL, and checks query limits. Use it to catch possible N+1 problems before merging your code.
Works with EF Core 8 and 10. See provider support.
Install
For ASP.NET Core integration tests:
dotnet add package QueryGuard.AspNetCore.Testing
Available on NuGet. For services and background jobs, use QueryGuard.Testing.
Check one request
Use your application's Program and AppDbContext types:
using Microsoft.AspNetCore.Mvc.Testing;
using QueryGuard;
using QueryGuard.AspNetCore.Testing;
using QueryGuard.Testing;
using var factory = new WebApplicationFactory<Program>();
await using var guard = factory.TrackQueries<Program, AppDbContext>(
"GET /api/companies",
QueryGuardPolicy.Create("companies").WithMaxOccurrencesPerFingerprint(5));
var response = await guard.Client.GetAsync("/api/companies");
response.EnsureSuccessStatusCode();
QueryGuardAssert.Passes(await guard.CompleteAsync());
The test fails if the same query runs more than five times. Always send requests through guard.Client.
Read a failure
QueryGuard FAILED: GET /api/companies (policy 'companies')
51 read queries in 2 distinct queries
[FAIL] max-occurrences-per-fingerprint: QG-FP-FDB5F469 executed 50 times; the budget is 5.
SQL: SELECT COUNT(*) FROM "Departments" AS "d" WHERE "d"."CompanyId" = ?
origin: samples/QueryGuard.SampleApi/Program.cs:line 89
The report shows the repeated query, its count, your limit, and where it ran. Repeated SQL can be intentional. Review each finding before changing the code.
Next steps
| Task | Guide |
|---|---|
| Measure requests, services, or jobs | Testing |
| Set query limits and capture options | Configuration |
| Compare query counts with a saved result | Baselines |
| Fix setup problems | Troubleshooting |
| Allow intentional repetition | When a finding is wrong |
| Understand sessions and query IDs | How it works |
| Browse types and methods | API reference |
Limits and privacy
QueryGuard captures relational EF Core commands. It does not capture Dapper or raw ADO.NET calls, prove an N+1 defect, or fix queries for you.
By default, reports exclude parameter values and redact SQL string and number values. Connection strings are not captured. See privacy settings.