dotnet-data Plugin: Data Access Skills for Entity Framework Core
The dotnet-data plugin currently provides one skill, optimizing-ef-core-queries, that teaches developers how to eliminate N+1 query patterns, apply AsNoTracking for read-only scenarios, and leverage compiled queries for high-performance Entity Framework Core data access.
The dotnet-data plugin in the dotnet/skills repository delivers targeted guidance for improving Entity Framework Core (EF Core) performance through a standardized skill-based architecture. Located in plugins/dotnet-data/, this plugin follows the repository's skill-plugin pattern to expose data access best practices via markdown-based skill definitions.
Plugin Architecture and Structure
The dotnet-data plugin adheres to the standard skill-plugin pattern used throughout the dotnet/skills repository. Its structure consists of a declaration file and skill-specific documentation that together expose optimization workflows to consuming tools.
plugin.json Configuration
The plugin.json file serves as the plugin's manifest, declaring the plugin name, version, description, and the path to the skills directory. Located at plugins/dotnet-data/plugin.json, this file enables discovery tools to identify available data access capabilities without parsing individual skill implementations.
Skill Definition Structure
Individual skills reside in the plugins/dotnet-data/skills/ directory, each implemented as a self-contained Markdown file with front-matter headers. The optimizing-ef-core-queries skill is defined in plugins/dotnet-data/skills/optimizing-ef-core-queries/SKILL.md, which includes invocation triggers, required inputs, step-by-step workflows, validation checklists, and executable code snippets.
The Optimizing EF Core Queries Skill
This skill provides a comprehensive workflow for diagnosing and resolving EF Core performance issues, specifically targeting query efficiency and database resource utilization.
When to Apply This Skill
Invoke this skill when your application exhibits slow query execution, database CPU or IO spikes, or when logs reveal N+1 query patterns. It is particularly valuable when LINQ queries generate excessive SQL statements or when ORM inefficiency impacts production performance.
Step-by-Step Optimization Workflow
The skill documentation in SKILL.md outlines a six-step optimization process:
- Enable detailed logging to capture generated SQL and identify bottlenecks.
- Eliminate N+1 queries through eager loading with
Include, query splitting withAsSplitQuery, or projection techniques. - Apply
AsNoTrackingfor read-only scenarios to disable change tracking overhead. - Cache compiled queries for frequently executed hot paths using
EF.CompileAsyncQuery. - Avoid common pitfalls such as client-side evaluation or premature
ToList()calls before filtering. - Drop to raw SQL using
FromSqlInterpolatedwhen LINQ cannot generate efficient database queries.
Code Implementation Examples
The following examples demonstrate the core techniques described in the optimizing-ef-core-queries skill.
Enable EF Core query logging to diagnose performance issues:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlServer(connectionString)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging() // dev only!
.EnableDetailedErrors();
Fix N+1 patterns by eager loading related entities:
var orders = await db.Orders
.Include(o => o.Items) // single query with JOIN
.AsSplitQuery() // split into two queries when many children
.ToListAsync();
Use AsNoTracking for read-only queries to improve performance:
var products = await db.Products
.AsNoTracking() // disables change tracking
.Where(p => p.IsActive)
.ToListAsync();
Compile and cache hot-path queries to eliminate recompilation overhead:
private static readonly Func<AppDbContext, int, Task<Order?>> GetOrderById =
EF.CompileAsyncQuery((AppDbContext ctx, int id) =>
ctx.Orders
.Include(o => o.Items)
.FirstOrDefault(o => o.Id == id));
var order = await GetOrderById(db, orderId); // fast, no recompilation cost
Avoid inefficient counting by using Any() for existence checks:
bool hasActiveUsers = await db.Users.AnyAsync(u => u.IsActive);
Execute parameterized raw SQL when LINQ cannot optimize the query:
var results = await db.Orders
.FromSqlInterpolated($@"
SELECT o.* FROM Orders o
INNER JOIN (
SELECT OrderId, SUM(Price) AS Total
FROM OrderItems
GROUP BY OrderId
HAVING SUM(Price) > {minTotal}
) t ON o.Id = t.OrderId")
.AsNoTracking()
.ToListAsync();
Summary
The dotnet-data plugin provides a focused set of data access optimizations for Entity Framework Core:
- Single skill focus: Currently implements
optimizing-ef-core-queriesinplugins/dotnet-data/skills/optimizing-ef-core-queries/SKILL.md - Performance-centric: Targets N+1 queries, tracking overhead, and query compilation
- Production-ready: Includes logging strategies, raw SQL fallbacks, and validation checklists
- Extensible architecture: New skills can be added by creating additional subdirectories under
plugins/dotnet-data/skills/
Frequently Asked Questions
What data access skills are included in the dotnet-data plugin?
The dotnet-data plugin currently contains one skill: optimizing-ef-core-queries. This skill provides a comprehensive guide to improving Entity Framework Core performance through query optimization techniques, tracking mode selection, and compiled query caching.
How does the plugin structure support additional data access skills?
The plugin follows a modular architecture where plugin.json declares the plugin metadata and points to the skills/ directory. New skills can be added by creating new subdirectories under plugins/dotnet-data/skills/, each containing a SKILL.md file with front-matter headers and implementation guides.
When should I use AsNoTracking versus standard query tracking?
Apply AsNoTracking for read-only scenarios where entities are not modified, such as display-only views or reporting queries. This reduces memory overhead and improves performance by disabling EF Core's change tracking mechanism. Use standard tracking when you need to update entities within the same context.
Can I use raw SQL with the optimization techniques described?
Yes, the skill explicitly includes FromSqlInterpolated as a fallback when LINQ cannot generate efficient SQL. This approach allows parameterized raw SQL execution while maintaining connection to the EF Core context and combining with other LINQ operations like AsNoTracking.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →