efcore-patterns

Entity Framework Core best practices including NoTracking by default, query splitting for navigation collections, migration management, dedicated migration services, and common pitfalls to avoid.

By aaronontheweb · 1,448 installs

npx skills add aaronontheweb/dotnet-skills --skill efcore-patterns

Source repository · Upstream listing

Entity Framework Core Patterns When to Use This Skill Use this skill when: Setting up EF Core in a new project Optimizing query performance Managing database migrations Integrating EF Core with .NET Aspire Debugging change tracking issues Loading multiple navigation collections efficiently (query splitting) Core Principles 1. NoTracking by Default Most queries are read only; opt in to tracking 2. Never Edit Migrations Manually Always use CLI commands 3. Dedicated Migration Service Separate migration execution from application startup 4. ExecutionStrategy for Retries Handle transient database failures 5. Explicit Updates When NoTracking, explicitly mark entities for update Pattern 1: NoTracking by Default Configure your DbContext to disable change tracking by default. This improves performance for read heavy workloads. When NoTracking is Active Read only queries work normally: Writes require explicit handling: When to Use Tracking Scenario Use Tracking? Why Display data in UI No Read only, no updates API GET endpoints No Returning data, no mutations Update single entity Yes or explicit Update() Need to save changes Complex update with navigation Yes Tracking handles relationships Batch operations No + ExecuteUpdate More efficient Explicit Add/Update Pattern Pattern 2: Never Edit Migrations Manually CRITICAL: Always use EF Core CLI commands to manage migrations. Never: Manually edit migration files (except for custom SQL in Up() / Down() ) Delete migration files directly Rename migration files Copy migrations between projects Creating Migrations Removing Migrations Applying Migrations Generating SQL Scripts Pattern 3: Dedicated Migration Service with Aspire Separate migration execution from your main application using a dedicated migration service. This ensures: Migrations complete before the app starts Clean separation of concerns Controlled seeding in test environments Project Structure MigrationService Program.cs MigrationWorker.cs AppHost Configuration Pattern 4: ExecutionStrategy for Transient Failures Always use CreateExecutionStrategy() for operations that might fail transiently: Important: You cannot use CreateExecutionStrategy() with user initiated transactions. If you need transactions with retry: Pattern 5: Bulk Operations with ExecuteUpdate/ExecuteDelete For bulk operations, use EF Core 7+ ExecuteUpdateAsync and ExecuteDeleteAsync instead of loading entities: Common Pitfalls 1. Forgetting to Update When NoTracking 2. N+1 Query Problem 3. Tracking Conflicts with Multiple DbContext Instances 4. Not Using Async Consistently 5. Querying Inside Loops DbContext Lifetime in DI ASP.NET Core (Scoped by Default) Background Services (Create Scope) Actors / Long Lived Objects (Factory Pattern) Pattern 6: Query Splitting to Prevent Cartesian Explosion When you load multiple navigation collections via Include() , EF Core generates a single query that can cause cartesian explosion. If you have 10 orders with 10 items each, you get 100 rows instead of 10 + 10. Global Configuration (Recommended for Most Cases) Enable query splitting globally in your DbContext configuration: Per Query Override Use single query when you know it's more efficient: Trade offs Behavior Pros Cons SplitQuery No cartesian explosion, better for large collections Multiple round trips, potential consistency issues SingleQuery Single round trip, transactional consistency Cartesian explosion with multiple collections Recommendation : Default to SplitQuery globally, override with AsSingleQuery() for specific queries where single query is known to be better. When to Prefer SingleQuery Small, well understood navigation graphs (2 3 levels) Queries where all related data is always needed Performance critical paths where round trip cost is lower than cartesian explosion When to Prefer SplitQuery Large or unpredictable navigation graphs Many to many relationships Queries loading collections that may not all be needed Testing with EF Core In Memory Provider (Unit Tests Only) Real Database with TestContainers (Integration Tests) See the testcontainers integration tests skill for proper database testing.