api-versioning
API versioning strategies for ASP.NET Core. Covers Asp.Versioning library, URL segment,…
Entity Framework Core patterns for .NET 10. Covers DbContext configuration, migrations workflow, interceptors, compiled queries, ExecuteUpdateAsync, ExecuteDeleteAsync, value converters, and query optimization. Load this skill when working with databases, writing queries,
$ npx -y skills add codewithmukesh/dotnet-claude-kit --skill ef-core --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/ef-coreContext preview
The summary Claude sees to decide when to auto-load this skill.
Entity Framework Core patterns for .NET 10. Covers DbContext configuration, migrations workflow, interceptors, compiled queries, ExecuteUpdateAsync, ExecuteDeleteAsync, value converters, and query optimization. Load this skill when working with databases, writing queries,
name: ef-core description: > Entity Framework Core patterns for .NET 10. Covers DbContext configuration, migrations workflow, interceptors, compiled queries, ExecuteUpdateAsync, ExecuteDeleteAsync, value converters, and query optimization. Load this skill when working with databases, writing queries, managing schema changes, or when the user mentions "EF Core", "Entity Framework", "DbContext", "migration", "LINQ query", "database", "SQL", "N+1", "Include", "split query", "value converter", "interceptor", or "compiled query".
1. **EF Core is the default ORM** — Use it unless you have a specific reason not to (extreme perf, legacy DB without FK constraints). See ADR-003. 2. **DbContext is a unit of work** — Don't wrap it in another UoW abstraction. EF Core already implements Unit of Work and Repository patterns internally. 3. **Queries should be projections** — Use `.Select()` to project into DTOs instead of loading full entities. This avoids over-fetching and N+1 issues. 4. **Migrations are code** — Treat them like any other source code. Review them, test them, never auto-apply in production.
Use `IEntityTypeConfiguration<T>` to keep entity configs separate and discoverable.
// Persistence/AppDbContext.cs
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
public DbSet<Order> Orders => Set<Order>();
public DbSet<Product> Products => Set<Product>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
}
// Persistence/Configurations/OrderConfiguration.cs
public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.HasKey(o => o.Id);
builder.Property(o => o.Total)
.HasPrecision(18, 2);
builder.HasMany(o => o.Items)
.WithOne()
.HasForeignKey(i => i.OrderId)
.OnDelete(DeleteBehavior.Cascade);
builder.HasIndex(o => o.CustomerId);
builder.HasIndex(o => o.CreatedAt);
}
}// Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("Default")));// GOOD — project to DTO, only loads needed columns
public async Task<OrderResponse?> GetOrderAsync(Guid id, CancellationToken ct)
{
return await db.Orders
.Where(o => o.Id == id)
.Select(o => new OrderResponse(
o.Id,
o.Total,
o.CreatedAt,
o.Items.Select(i => new OrderItemResponse(i.ProductName, i.Quantity, i.Price)).ToList()))
.FirstOrDefaultAsync(ct);
}public async Task<PagedList<OrderSummary>> ListOrdersAsync(int page, int pageSize, CancellationToken ct)
{
var query = db.Orders
.OrderByDescending(o => o.CreatedAt)
.Select(o => new OrderSummary(o.Id, o.CustomerName, o.Total, o.Status));
var totalCount = await query.CountAsync(ct);
var items = await query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync(ct);
return new PagedList<OrderSummary>(items, totalCount, page, pageSize);
}Bulk operations that bypass change tracking for better performance.
// Update without loading entities
await db.Orders
.Where(o => o.Status == OrderStatus.Pending && o.CreatedAt < cutoff)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.Status, OrderStatus.Expired)
.SetProperty(o => o.UpdatedAt, clock.GetUtcNow()),
ct);
// Delete without loading entities
await db.Orders
.Where(o => o.Status == OrderStatus.Cancelled && o.CreatedAt < archiveCutoff)
.ExecuteDeleteAsync(ct);Use interceptors for cross-cutting concerns like audit trails and soft deletes.
public class AuditInterceptor(TimeProvider clock) : SaveChangesInterceptor
{
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken ct = default)
{
var context = eventData.Context;
if (context is null) return ValueTask.FromResult(result);
var now = clock.GetUtcNow();
foreach (var entry in context.ChangeTracker.Entries<IAuditable>())
{
switch (entry.State)
{
case EntityState.Added:
entry.Entity.CreatedAt = now;
entry.Entity.UpdatedAt = now;
break;
case EntityState.Modified:
entry.Entity.UpdatedAt = now;
break;
}
}
return ValueTask.FromResult(result);
}
}
// Registration
builder.Services.AddDbContext<AppDbContext>((sp, options) =>
options
.UseNpgsql(connectionString)
.AddInterceptors(sp.GetRequiredService<AuditInterceptor>()));Use for hot-path queries that execute frequently with the same shape.
public class OrderQueries
{
public static readonly Func<AppDbContext, Guid, CancellationToken, Task<Order?>> GetById =
EF.CompileAsyncQuery((AppDbContext db, Guid id, CancellationToken ct) =>
db.Orders
.Include(o => o.Items)
.FirstOrDefault(o => o.Id == id));
}
// Usage
var order = await OrderQueries.GetById(db, orderId, ct);// Store enum as string
builder.Property(o => o.Status)
.HasConversion<string>()
.HasMaxLength(50);
// Strongly-typed IDs
public readonly record struct OrderId(Guid Value);
builder.Property(o => o.API versioning strategies for ASP.NET Core. Covers Asp.Versioning library, URL segment,…
Architecture conformance check: verifies an existing codebase against its declared…
Architecture selection advisor for .NET applications. Asks structured questions about domain…
.NET Aspire for cloud-native orchestration. Covers AppHost configuration, service defaults,…
Authentication and authorization for ASP.NET Core. Covers JWT bearer tokens, OpenID Connect,…
Autonomous iteration loops for .NET: drive a broken build or failing test suite to green with…