一键导入
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 页面并帮你完成安装。
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.
基于 SOC 职业分类
| 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>() |