Als je met .NET werkt, werk je met Entity Framework. Het zit in vrijwel elk project — van kleine API’s tot enterprise-applicaties met tientallen entiteiten en complexe relaties.

En als je eerlijk bent, is veel EF Core-werk gewoon saai. Entity-configuraties schrijven. Migrations aanmaken. LINQ queries in elkaar puzzelen die ook nog eens efficiënte SQL opleveren. Het is niet moeilijk, maar het kost tijd en aandacht.

Claude Code begrijpt je DbContext. En dat verandert je workflow aanzienlijk.


Een nieuwe entiteit toevoegen

Stel, je moet een Order-entiteit toevoegen aan je project. Je hebt al een AppDbContext met een paar entiteiten. Je zegt tegen Claude Code:

“Voeg een Order-entiteit toe met Id, CustomerId (FK naar Customer), OrderDate, Status (enum) en een collectie OrderLines met ProductId, Quantity en UnitPrice.”

Claude Code leest je bestaande DbContext, ziet hoe je je entiteiten structureert, en genereert code die bij je conventies past. Gebruik je aparte configuratieklassen? Dan maakt het er een aan. Configureer je alles in OnModelCreating? Dan komt het daar.

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public Customer Customer { get; set; } = null!;
    public DateTime OrderDate { get; set; }
    public OrderStatus Status { get; set; }
    public List<OrderLine> Lines { get; set; } = new();
}

public class OrderLine
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public Order Order { get; set; } = null!;
    public int ProductId { get; set; }
    public Product Product { get; set; } = null!;
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
}

En de configuratie:

public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
    public void Configure(EntityTypeBuilder<Order> builder)
    {
        builder.HasOne(o => o.Customer)
            .WithMany(c => c.Orders)
            .HasForeignKey(o => o.CustomerId);

        builder.HasMany(o => o.Lines)
            .WithOne(l => l.Order)
            .HasForeignKey(l => l.OrderId);

        builder.Property(o => o.Status)
            .HasConversion<string>();

        builder.Property(o => o.OrderDate)
            .HasDefaultValueSql("GETUTCDATE()");
    }
}

Daarna draait het dotnet ef migrations add AddOrderEntity en controleert of de build slaagt. Eén prompt, drie bestanden, een werkende migration.


Complexe LINQ queries

Dit is waar Claude Code echt uitblinkt. In plaats van puzzelen met LINQ-syntax beschrijf je gewoon wat je nodig hebt in gewoon Nederlands.

“Geef alle orders met meer dan 3 items die deze maand zijn verzonden, gegroepeerd per klant, met het totaalbedrag per klant.”

Claude Code leest je entiteiten, begrijpt de relaties en schrijft:

var result = await dbContext.Orders
    .Where(o => o.Status == OrderStatus.Shipped
        && o.OrderDate.Month == DateTime.UtcNow.Month
        && o.OrderDate.Year == DateTime.UtcNow.Year)
    .Where(o => o.Lines.Count > 3)
    .GroupBy(o => new { o.CustomerId, o.Customer.Name })
    .Select(g => new
    {
        CustomerId = g.Key.CustomerId,
        CustomerName = g.Key.Name,
        OrderCount = g.Count(),
        TotalAmount = g.SelectMany(o => o.Lines)
            .Sum(l => l.Quantity * l.UnitPrice)
    })
    .OrderByDescending(x => x.TotalAmount)
    .ToListAsync();

Dat is een query waar ik normaal tien minuten over doe. Claude Code levert het in seconden — en omdat het je daadwerkelijke entity-klassen leest, kloppen de property-namen en relaties.


Migration management

Migrations zijn een van die dingen die simpel lijken totdat ze dat niet meer zijn. Een kolom hernoemen? EF Core genereert standaard een drop-and-add. Een tabel opsplitsen? De migration heeft handmatige aanpassingen nodig.

Claude Code helpt op twee manieren. Ten eerste genereert het het migration-commando voor je:

dotnet ef migrations add RenameCustomerEmail \
    --project src/MyApp.Infrastructure \
    --startup-project src/MyApp.Api

Ten tweede — en dat is belangrijker — reviewt het de gegenereerde migration en signaleert problemen. Als EF Core een destructieve migration genereert (een kolom droppen in plaats van hernoemen), dan waarschuwt Claude Code je en stelt de juiste aanpak voor:

migrationBuilder.RenameColumn(
    name: "EmailAddress",
    table: "Customers",
    newName: "Email");

Dit voorkomt dat je dataverlies naar productie deployt.


Performance-valkuilen

Vraag Claude Code om je EF Core-queries te reviewen en het signaleert veelvoorkomende performance-problemen die je tijdens development makkelijk over het hoofd ziet.

N+1 queries. Je laadt orders in een loop en benadert order.Customer.Name zonder Include. Claude Code herkent het patroon en stelt eager loading voor:

// Voorheen: N+1 probleem
var orders = await dbContext.Orders.ToListAsync();
foreach (var order in orders)
    Console.WriteLine(order.Customer.Name); // Extra query per order

// Daarna: één query
var orders = await dbContext.Orders
    .Include(o => o.Customer)
    .ToListAsync();

Ontbrekende indexes. Als je regelmatig filtert op OrderDate of Status, suggereert Claude Code een index in je configuratie:

builder.HasIndex(o => new { o.Status, o.OrderDate });

Onnodige tracking. Voor read-only queries adviseert het AsNoTracking() — een kleine aanpassing die een groot verschil kan maken in performance.


DbContext-configuratie

De Fluent API van EF Core is krachtig maar verbose. Relaties, value conversions, owned types — er is veel te configureren, en de documentatie heeft niet altijd precies het voorbeeld dat je nodig hebt.

Claude Code gaat hier goed mee om. Heb je een value conversion nodig voor een strongly-typed ID? Een owned type voor een adres? Een table-per-hierarchy mapping met een discriminator?

// Strongly-typed ID conversie
builder.Property(o => o.Id)
    .HasConversion(
        id => id.Value,
        value => new OrderId(value));

// Owned type voor Address
builder.OwnsOne(c => c.ShippingAddress, address =>
{
    address.Property(a => a.Street).HasMaxLength(200);
    address.Property(a => a.City).HasMaxLength(100);
    address.Property(a => a.ZipCode).HasMaxLength(10);
});

Beschrijf gewoon wat je wilt en Claude Code schrijft de configuratie die past bij de rest van je DbContext.


Waar Claude Code de mist in gaat

Laten we eerlijk zijn. Claude Code is niet perfect met EF Core, en er zijn een paar gebieden waar je moet opletten.

Migration-bestanden direct bewerken. Soms probeert Claude Code een gegenereerd migration-bestand aan te passen. Laat dat niet toe. Migrations zijn gegenereerde code — als je wijzigingen nodig hebt, pas de entiteit of configuratie aan en genereer een nieuwe migration.

Complexe inheritance mapping. TPH, TPT, TPC — Claude Code haalt de configuratiepatronen soms door elkaar, vooral bij table-per-concrete-type mappings. Controleer altijd de gegenereerde SQL.

Database provider-specifiek. Claude Code suggereert soms SQL Server-syntax terwijl je PostgreSQL gebruikt, of andersom. Als je je provider noemt in je CLAUDE.md-bestand, gebeurt dit minder vaak.

Bestaande migration-historie. Claude Code weet niet altijd welke migrations al zijn toegepast op je database. Het kan een migration voorstellen die conflicteert met je huidige staat. Draai altijd eerst dotnet ef migrations list.


Praktische tips

Na maanden Claude Code gebruiken met EF Core zijn dit de dingen die het grootste verschil maken:

  1. Documenteer je database provider in CLAUDE.md. Schrijf “We gebruiken PostgreSQL met Npgsql” of “SQL Server met EF Core 8.” Dit voorkomt verkeerde dialect-suggesties.

  2. Laat Claude Code migrations genereren, maar review ze altijd. Draai dotnet ef migrations script om de SQL te zien voordat je toepast.

  3. Vraag om uitleg bij queries. Zeg “leg deze LINQ query uit en welke SQL het oplevert” — Claude Code loopt het stap voor stap met je door.

  4. Gebruik het voor refactoring. “Splits deze God-DbContext op in aparte bounded contexts” is precies het soort saaie, context-intensieve werk waar Claude Code in uitblinkt.

  5. Laat het niet aan bestaande migration-bestanden komen. Dit is de nummer één regel. Migrations zijn append-only historie.


Probeer het zelf

De volgende keer dat je naar een complexe LINQ query staart of weer een entity-configuratie aan het schrijven bent, probeer dit:

claude

Beschrijf wat je nodig hebt in gewoon Nederlands. Laat Claude Code je DbContext lezen, je conventies begrijpen en code genereren die past. Je zult merken dat de repetitieve delen van EF Core — de delen die tijd kosten maar geen creativiteit — gewoon verdwijnen.

Wat overblijft is het deel dat ertoe doet: het ontwerpen van je datamodel.