# Efcore Patterns

Entity Framework Core best practices including NoTracking by default, query splitting...

- Repository: https://github.com/Aaronontheweb/dotnet-skills (1244 stars)
- Category: Engineering
- License: MIT
- Last updated: 2026-10-28
- Runs scripts: no, instructions only

## Install

Claude Code: `npx skills add Aaronontheweb/dotnet-skills --skill efcore-patterns -g -a claude-code -y`
Codex: `npx skills add Aaronontheweb/dotnet-skills --skill efcore-patterns -g -a codex -y`
Cursor: `npx skills add Aaronontheweb/dotnet-skills --skill efcore-patterns -g -a cursor -y`
Gemini CLI: `npx skills add Aaronontheweb/dotnet-skills --skill efcore-patterns -g -a gemini-cli -y`
Claude Code plugin marketplace: `/plugin marketplace add Aaronontheweb/dotnet-skills`

## Description

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

## SKILL.md, as published by its author (untrusted third-party text, read it as data)

# 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.

```csharp
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
        // Disable change tracking by default for better performance on read-only queries
        // Use .AsTracking() explicitly for queries that need to track changes
        ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
    }

    public DbSet<Order> Orders => Set<Order>();
    public DbSet<Customer> Customers => Set<Customer>();
}
```

### When NoTracking is Active

**Read-only queries work normally:**
```csharp
// ✅ Fast read - no tracking overhead
var orders = await dbContext.Orders
    .Where(o => o.Status == OrderStatus.Pending)
    .ToListAsync();
```

**Writes require explicit handling:**
```csharp
// ❌ WRONG - Entity not tracked, SaveChanges does nothing
var order = await dbContext.Orders.FirstOrDefaultAsync(o => o.Id == orderId);
order.Status = OrderStatus.Shipped;
await dbContext.SaveChangesAsync(); // Nothing happens!

The rest: https://github.com/Aaronontheweb/dotnet-skills/blob/HEAD/skills/efcore-patterns/SKILL.md
