ワンクリックで
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>() |