plugins/languages/csharp/skills/data/SKILL.md
C# 数据访问与 ORM 规范。覆盖 EF Core 10 compiled queries、JSON columns、 complex types、bulk operations (ExecuteUpdate / ExecuteDelete)、SaveChanges interceptors、迁移策略、连接池、TestContainers 集成测试、Dapper micro-ORM 选型、 EF Core 10 Vector / Native AOT。当访问数据库、设计数据模型、调优查询性能、 写迁移脚本、配置 DbContext, 或说 "EF Core"、"Entity Framework"、"DbContext"、 "migration"、"Dapper"、"Npgsql"、"SqlServer"、"compiled query" 时加载。
npx skillsauth add lazygophers/ccplugin csharp-dataInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
EF Core 10 为主线; 高频热点 + 复杂报表用 Dapper。
public class AppDb(DbContextOptions<AppDb> opts) : DbContext(opts)
{
public DbSet<Order> Orders => Set<Order>();
public DbSet<Customer> Customers => Set<Customer>();
protected override void OnModelCreating(ModelBuilder b)
{
b.ApplyConfigurationsFromAssembly(typeof(AppDb).Assembly);
}
}
// Program.cs
builder.Services.AddDbContextPool<AppDb>(o => o
.UseNpgsql(conn, npg => npg.EnableRetryOnFailure())
.EnableSensitiveDataLogging(env.IsDevelopment())
.ConfigureWarnings(w => w.Throw(RelationalEventId.MultipleCollectionIncludeWarning)));
AddDbContextPool 减少分配; ctor 仅接受 DbContextOptions<T>IEntityTypeConfiguration<T> 文件, 不塞 OnModelCreating.UseModel()Guid (UUIDv7) 或 long (Snowflake); 避免暴露自增整数complex type (EF Core 8+) 或 owned entityb.HasQueryFilter(e => !e.IsDeleted)SaveChangesInterceptorpublic sealed class AuditInterceptor : SaveChangesInterceptor
{
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData e, InterceptionResult<int> r, CancellationToken ct = default)
{
foreach (var entry in e.Context!.ChangeTracker.Entries<IAuditable>())
{
if (entry.State == EntityState.Added) entry.Entity.CreatedAt = DateTime.UtcNow;
if (entry.State == EntityState.Modified) entry.Entity.UpdatedAt = DateTime.UtcNow;
}
return base.SavingChangesAsync(e, r, ct);
}
}
AsNoTracking(); 写路径走跟踪MultipleCollectionIncludeWarning 为 ThrowAsSplitQuery() 避免笛卡尔积.ToList() 后内存过滤; 下推到 SQLAsAsyncEnumerable() + await foreachvar dtos = await db.Orders.AsNoTracking()
.Where(o => o.CustomerId == cid && o.CreatedAt >= since)
.OrderByDescending(o => o.CreatedAt)
.Select(o => new OrderListDto(o.Id, o.Amount, o.CreatedAt))
.ToListAsync(ct);
热路径用编译查询消除表达式树编译开销:
private static readonly Func<AppDb, long, CancellationToken, Task<Order?>> GetOrderById =
EF.CompileAsyncQuery((AppDb db, long id, CancellationToken ct) =>
db.Orders.AsNoTracking().FirstOrDefault(o => o.Id == id));
EF Core 8+ 内置 JSON 映射, 简化半结构化字段:
b.OwnsOne(c => c.Preferences, p => p.ToJson());
b.OwnsMany(c => c.PhoneNumbers, p => p.ToJson());
可在 LINQ 中直接查询 JSON 内属性 (Provider 支持时下推为 SQL JSON 操作)。
b.Property(d => d.Embedding).HasVector(1536);
var nearest = await db.Documents
.OrderBy(d => d.Embedding.CosineDistance(query))
.Take(10).ToListAsync(ct);
await db.Orders
.Where(o => o.Status == OrderStatus.Cancelled && o.UpdatedAt < cutoff)
.ExecuteDeleteAsync(ct);
await db.Products.Where(p => p.Discontinued)
.ExecuteUpdateAsync(s => s.SetProperty(p => p.Price, p => p.Price * 0.5m), ct);
大量插入用 EFCore.BulkExtensions 或直接 COPY / BULK INSERT。
var strategy = db.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
await using var tx = await db.Database.BeginTransactionAsync(ct);
// ...
await db.SaveChangesAsync(ct);
await tx.CommitAsync(ct);
});
ExecutionStrategy 处理 retry 重试; 不要手写循环。
AddOrderStatusIndexdotnet ef migrations script --idempotent 给 DBA 评审if (env.IsDevelopment())
{
using var scope = app.Services.CreateScope();
await scope.ServiceProvider.GetRequiredService<AppDb>().Database.MigrateAsync();
}
appsettings.json + User Secrets / Azure Key Vault; 不入 git| 用 EF Core | 用 Dapper | |-----------|-----------| | CRUD、聚合根 | 复杂报表、多表 join 投影 | | 跟踪变更 | 只读热路径 | | 迁移与建表 | 存储过程调用 |
const string sql = """
SELECT o.id, o.amount, c.name AS customer_name
FROM orders o JOIN customers c ON c.id = o.customer_id
WHERE o.created_at >= @since
ORDER BY o.amount DESC LIMIT 100
""";
await using var conn = await dataSource.OpenConnectionAsync(ct);
var rows = await conn.QueryAsync<OrderReport>(
new CommandDefinition(sql, new { since }, cancellationToken: ct));
Respawn 在每个测试前清表WebApplicationFactory + per-test transaction rollback 也是常见方案var pg = new PostgreSqlBuilder().WithImage("postgres:17").Build();
await pg.StartAsync();
tools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。