원클릭으로
ef-core-basics
Use when configuring EF Core DbContext, entity configuration, or connection resiliency.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Use when configuring EF Core DbContext, entity configuration, or connection resiliency.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use when adding caching to .NET APIs or optimizing response times with distributed cache, output cache, or ETags.
Use when configuring API response formats, custom formatters, or Accept header handling.
Use when building controller-based REST APIs with action results, model binding, or MediatR integration.
Use when creating RESTful API controllers with MediatR dispatch and ProblemDetails error responses.
Use when designing gRPC services, proto files, or adding gRPC-Web or JSON transcoding.
Use when building minimal API endpoints with route groups, filters, or TypedResults.
| name | ef-core-basics |
| description | Use when configuring EF Core DbContext, entity configuration, or connection resiliency. |
| metadata | {"category":"data","agent":"ef-specialist","when-to-use":"When configuring EF Core DbContext, entity configurations, migrations"} |
IEntityTypeConfiguration<T> for fluent configuration in separate filespublic sealed class AppDbContext(
DbContextOptions<AppDbContext> options) : DbContext(options)
{
public DbSet<Order> Orders => Set<Order>();
public DbSet<Product> Products => Set<Product>();
public DbSet<Customer> Customers => Set<Customer>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(
typeof(AppDbContext).Assembly);
}
}
internal sealed class OrderConfiguration
: IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.HasKey(o => o.Id);
// Strongly-typed ID conversion
builder.Property(o => o.Id)
.HasConversion(
id => id.Value,
value => new OrderId(value));
builder.Property(o => o.CustomerName)
.HasMaxLength(200)
.IsRequired();
builder.Property(o => o.Status)
.HasConversion<string>()
.HasMaxLength(50);
// Row version for concurrency
builder.Property(o => o.RowVersion)
.IsRowVersion();
// Relationships
builder.HasMany(o => o.Items)
.WithOne()
.HasForeignKey(i => i.OrderId)
.OnDelete(DeleteBehavior.Cascade);
// Soft delete filter
builder.HasQueryFilter(o => !o.IsDeleted);
// Indexes
builder.HasIndex(o => o.CustomerName);
builder.HasIndex(o => o.CreatedAt);
}
}
// Strongly-typed ID converter
internal sealed class OrderIdConverter
: ValueConverter<OrderId, Guid>
{
public OrderIdConverter()
: base(id => id.Value, value => new OrderId(value)) { }
}
// Value object converter (owned type is preferred for complex VOs)
builder.OwnsOne(o => o.ShippingAddress, address =>
{
address.Property(a => a.Street).HasMaxLength(200);
address.Property(a => a.City).HasMaxLength(100);
address.Property(a => a.ZipCode).HasMaxLength(20);
});
builder.Services.AddDbContext<AppDbContext>((sp, options) =>
{
options.UseSqlServer(
builder.Configuration.GetConnectionString("Default"),
sql =>
{
sql.EnableRetryOnFailure(
maxRetryCount: 3,
maxRetryDelay: TimeSpan.FromSeconds(5),
errorNumbersToAdd: null);
sql.CommandTimeout(30);
sql.MigrationsAssembly(
typeof(AppDbContext).Assembly.FullName);
});
options.AddInterceptors(
sp.GetRequiredService<AuditableInterceptor>(),
sp.GetRequiredService<DomainEventInterceptor>());
});
// PostgreSQL alternative
options.UseNpgsql(connectionString, npgsql =>
{
npgsql.EnableRetryOnFailure(3);
npgsql.CommandTimeout(30);
});
public sealed class DomainEventInterceptor(IPublisher publisher)
: SaveChangesInterceptor
{
public override async ValueTask<int> SavedChangesAsync(
SaveChangesCompletedEventData eventData,
int result,
CancellationToken ct = default)
{
var context = eventData.Context!;
var aggregates = context.ChangeTracker
.Entries<AggregateRoot<object>>()
.Where(e => e.Entity.DomainEvents.Count != 0)
.Select(e => e.Entity)
.ToList();
foreach (var aggregate in aggregates)
{
foreach (var domainEvent in aggregate.DomainEvents)
await publisher.Publish(domainEvent, ct);
aggregate.ClearDomainEvents();
}
return result;
}
}
// For running migrations from CLI without the app host
internal sealed class AppDbContextFactory
: IDesignTimeDbContextFactory<AppDbContext>
{
public AppDbContext CreateDbContext(string[] args)
{
var config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile("appsettings.Development.json", optional: true)
.Build();
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlServer(config.GetConnectionString("Default"))
.Options;
return new AppDbContext(options);
}
}
OnModelCreating directly (use separate configuration files)IsRequired() / HasMaxLength() (relies on nullable annotations only)string for enums in the database without explicit conversion: DbContext class inheritanceUseSqlServer or UseNpgsql in Program.csIEntityTypeConfiguration<T> implementationsMigrations/ folderSaveChangesInterceptor implementationsApplyConfigurationsFromAssemblyIEntityTypeConfiguration<T>| Scenario | Approach |
|---|---|
| Strongly-typed ID | HasConversion with ValueConverter |
| Complex value object | OwnsOne owned entity |
| Soft delete | Global query filter |
| Concurrency | IsRowVersion() or IsConcurrencyToken() |
| Enum storage | HasConversion<string>() |