一键导入
data-access
EF Core configuration, value object embedding, DbUp migrations, Aspire setup. Use when modifying database schema, migrations, or data access code.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
EF Core configuration, value object embedding, DbUp migrations, Aspire setup. Use when modifying database schema, migrations, or data access code.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Minimal API endpoint patterns with IEndpointDefinition, filters, error handling. Use when creating or modifying API endpoints.
Perform a thorough architecture review of a .NET project examining structure, maintainability, clarity, robustness, and goal achievement. Use when the user asks to review, audit, or examine a codebase.
CQRS implementation — commands use EF Core DbContext, queries use Dapper IDbConnection. Use when implementing or modifying command/query handlers.
Perform a thorough architecture review of a .NET project examining structure, maintainability, clarity, robustness, and goal achievement. Use when the user asks to review, audit, or examine a codebase.
Domain entity and value object patterns — private setters, factory methods, Reconstitute. Use when creating or modifying domain models.
Debugging workflow, Docker dual-runtime requirements, dev tunnels, local CI. Use when debugging issues or working with deployment configuration.
| name | data-access |
| description | EF Core configuration, value object embedding, DbUp migrations, Aspire setup. Use when modifying database schema, migrations, or data access code. |
| user-invocable | false |
Value Object Embedding with OwnsOne:
// Product configuration
modelBuilder.Entity<Product>()
.OwnsOne(p => p.Price, priceBuilder => {
priceBuilder.Property(m => m.Amount).HasColumnName("price_amount");
priceBuilder.Property(m => m.Currency).HasColumnName("price_currency");
});
// Customer configuration
modelBuilder.Entity<Customer>()
.OwnsOne(c => c.Email, emailBuilder => {
emailBuilder.Property(e => e.Value).HasColumnName("email");
});
Aggregate Navigation Properties with backing field access:
// Order → OrderItems: EF Core manages FK, backing field stores collection
modelBuilder.Entity<Order>(orderBuilder => {
orderBuilder.HasMany(o => o.Items)
.WithOne()
.HasForeignKey(oi => oi.OrderId)
.OnDelete(DeleteBehavior.Cascade);
orderBuilder.Navigation(o => o.Items)
.UsePropertyAccessMode(PropertyAccessMode.Field);
});
This lets the aggregate root own the collection privately (_items backing field) while EF Core populates it via .Include(). Items added through Order.AddItem() get their OrderId set by EF on save — no need to know the ID upfront.
Optimistic Concurrency:
Use PostgreSQL xmin concurrency tokens for entities whose stale writes can corrupt state or inventory. Order and Product expose a uint RowVersion property with a private setter and their EF configurations map it to the xmin system column with .IsRowVersion(). DbUpdateConcurrencyException maps to 409 Conflict at the API boundary.
builder.Property(o => o.RowVersion)
.HasColumnName("xmin")
.IsRowVersion();
DbUp with Embedded Scripts:
DbMigrator project0001_CreateTables.sql, 0002_AddIndexes.sqlConstraint Naming Convention (enforced by convention test from the first PostgreSQL migration onward):
Every constraint must be explicitly named. Anonymous/system-generated names require dynamic SQL to discover and drop, which is fragile and non-deterministic.
| Prefix | Type | Example |
|---|---|---|
pk_ | Primary Key | CONSTRAINT pk_orders PRIMARY KEY (id) |
fk_ | Foreign Key | CONSTRAINT fk_orders_customer_id FOREIGN KEY (customer_id) REFERENCES customers(id) |
df_ | Default | CONSTRAINT df_orders_status DEFAULT 'Pending' |
ck_ | Check | CONSTRAINT ck_products_stock_non_negative CHECK (stock >= 0) |
ix_ | Index | CREATE INDEX ix_orders_order_date ON orders (order_date DESC) |
In ALTER TABLE ... ADD statements, use the ADD CONSTRAINT form:
ALTER TABLE orders ADD CONSTRAINT ck_orders_status CHECK (status IN ('Pending', 'Confirmed', 'Processing', 'Shipped', 'Delivered', 'Cancelled'));
Two resolvers, each in its own Program.cs:
src/StarterApp.Api/Program.cs) resolves only database and throws if it is absent (GetConnectionString("database") ?? throw new InvalidOperationException(...)) — it relies on Aspire injecting the connection string, so there is no local fallback.src/StarterApp.DbMigrator/Program.cs) resolves a fallback chain database → postgres → DefaultConnection (databaseConnection ?? postgresConnection ?? defaultConnection), with DefaultConnection serving as the local appsettings.json fallback for standalone migration runs.aspire update for automatic package updatesvar builder = DistributedApplication.CreateBuilder(args);
var postgres = builder.AddPostgres("postgres")
.WithLifetime(ContainerLifetime.Persistent);
var database = postgres.AddDatabase("database");
var api = builder.AddProject<Projects.StarterApp_Api>("api")
.WithReference(database)
.WaitFor(database);
var migrator = builder.AddProject<Projects.StarterApp_DbMigrator>("migrator")
.WithReference(database)
.WaitFor(database);
builder.Build().Run();
Shared cross-cutting concerns: