.claude/skills/debug-ef-query/SKILL.md
Use when diagnosing slow EF Core queries, N+1 problems, or unexpected SQL generation. Covers query logging, AsNoTracking, Include chains, projection fixes, and compiled queries. Invoke when a LINQ query generates more SQL than expected, a page loads slowly due to database calls, Include chains produce Cartesian explosion, or tracking is unnecessary on read-only queries. Also trigger when the user asks: why is my EF query slow, N+1 problem, fix EF query, EF SQL logging, AsNoTracking, Include performance, compiled query, EF Core optimization. Domain: EF Core / Data Access. Level: Intermediate.
npx skillsauth add klod68/littlerae debug-ef-queryInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
// In DbContext options (development only)
optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
Capture the generated SQL for the problem query before doing anything else.
| Symptom | Likely cause |
|---|---|
| Many identical queries in a loop | N+1 — missing Include() or batching |
| Query returns more columns than needed | Missing Select() projection |
| Full table scan in logs | Missing index or EF can't translate filter |
| Tracking overhead on reads | Missing AsNoTracking() |
| Cartesian explosion | Multiple collection Include() on same query |
| InvalidOperationException on async | .Result / .Wait() deadlock |
// Before (N+1)
var orders = await context.Orders.ToListAsync();
foreach (var o in orders) { _ = o.Customer.Name; } // lazy load per row
// After
var orders = await context.Orders
.Include(o => o.Customer)
.AsNoTracking()
.ToListAsync(ct);
// Before
var entities = await context.Products.ToListAsync(ct);
var dtos = entities.Select(e => new ProductDto(e.Id, e.Name)).ToList();
// After
var dtos = await context.Products
.AsNoTracking()
.Select(e => new ProductDto(e.Id, e.Name))
.ToListAsync(ct);
context.Orders
.Include(o => o.Lines)
.Include(o => o.Shipments)
.AsSplitQuery() // generates separate SQL per collection
.AsNoTracking()
// Document WHY LINQ was insufficient before using raw SQL
var results = await context.Products
.FromSqlRaw("SELECT * FROM Products WHERE FullTextMatch(@term)", term)
.AsNoTracking()
.ToListAsync(ct);
AsNoTracking() is present on all read paths.AsNoTracking() on all read-only queriesSelect) used instead of full entity load where applicableInclude() chains deeper than 2 levelstools
Use when cross-cutting concerns (logging, metrics, validation, authorization) are tangled into command handlers or service methods, when building database command pipelines with reorderable concerns, or when HTTP client pipelines or message handlers need composable, independently-replaceable processing stages. Covers ICommandInterceptor interface, InterceptorPipeline with reverse-chain construction, zero-cost Empty sentinel to skip overhead when no interceptors are registered, and ConfigureAwait(false) discipline for library code. Domain: Architecture, Cross-Cutting Concerns. Level: Intermediate. Tags: interceptor, pipeline, middleware, decorator, cross-cutting-concerns.
development
Use when writing integration tests for Razor Pages, MVC, or Minimal API applications to validate routing, middleware, page rendering, and HTTP behavior without a browser or live server, or when adding fast smoke tests to a CI pipeline. Covers WebApplicationFactory<Program> setup with public partial class Program, in-memory test server, AngleSharp HTML parsing, CSS selector assertions, redirect and status code testing, and a shared static fixture pattern for minimal per-test startup overhead. Domain: Testing, ASP.NET Core. Level: Intermediate. Tags: integration-testing, webapplicationfactory, razor-pages, anglesharp, http-testing.
development
Use when designing indexes for new tables, diagnosing slow queries that are not using indexes efficiently, reviewing index fragmentation and maintenance, or when the current indexing strategy results in key lookups, table scans, or missing index warnings. Covers clustered index key selection (narrow, unique, ever-increasing), non-clustered index design for query patterns, covering indexes with INCLUDE columns, filtered indexes for subset queries, composite index column ordering, DMV-based monitoring for missing and unused indexes, and rebuild vs reorganize maintenance thresholds. Domain: Database, Performance. Level: Intermediate. Tags: index, sql-server, covering-index, filtered-index, performance, dmv, maintenance.
development
Use when building a searchable in-memory catalog or registry for documentation sites, admin panels, or type/API browsers where you need keyword matching, fuzzy search, and ranked results without an external search engine or database. Covers RegistryService with weighted scoring across name, description, keywords, and method names; Levenshtein fuzzy matching; synonym expansion; category and subcategory filtering; and singleton DI registration for datasets of hundreds to low thousands of items. Domain: Search, Data Access Patterns. Level: Intermediate. Tags: search, registry, fuzzy-matching, in-memory, catalog, filtering.