
使用 GitHub Copilot 掌握 Entity Framework Core 最佳实践从 DbContext 设计到迁移与性能优化【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot导读本文基于 skills/ef-core/SKILL.md 这份社区贡献的 GitHub Copilot 技能文档系统梳理 Entity Framework CoreEF Core开发中的核心最佳实践覆盖数据上下文设计、实体建模、查询性能、迁移管理、变更跟踪、安全与测试八个维度。本文同时结合当前仓库中 efcore-d2-db-diagram 技能与 dotnet-best-practices 等配套资源深入讲解每条实践背后的原理与落地方式。读完本文你将能够在 Copilot 辅助下完成 EF Core 代码评审、识别典型反模式并掌握可复用的性能与架构改进方案。一、技能文档定位让 Copilot 成为 EF Core 代码评审员skills/ef-core/SKILL.md定义了一个名为ef-core的 Copilot 技能其描述为Get best practices for Entity Framework Core获取 Entity Framework Core 的最佳实践。技能的使命非常明确Your goal is to help me follow best practices when working with Entity Framework Core.也就是说当你在对话中启用该技能并提交 EF Core 代码后Copilot 的角色是识别代码中不符合最佳实践的问题并给出遵循这些最佳实践的改进建议。这与仓库中 dotnet-best-practices 技能的定位一脉相承——后者负责确保 .NET/C# 代码整体满足项目级规范如依赖注入、异步模式、参数化查询等而ef-core技能则聚焦数据访问层。该技能把 EF Core 最佳实践组织为八个主题数据上下文设计Data Context Design、实体设计Entity Design、性能Performance、迁移Migrations、查询Querying、变更跟踪与保存Change Tracking Saving、安全Security、测试Testing。下文逐主题展开并结合仓库源码佐证其底层原理。二、Data Context Design如何设计一个聚焦且易维护的 DbContext原文档给出的数据上下文设计要点如下保持 DbContext 类聚焦且内聚Keep DbContext classes focused and cohesive一个 DbContext 应对应一个明确的领域范围或限界上下文而不是把所有实体塞进同一个类。实践中常按业务模块拆分多个 DbContext如BillingContext、IdentityContext避免单一巨型上下文带来的启动变慢、模型混乱与变更互相干扰。使用构造函数注入来传递配置选项Use constructor injection for configuration optionsDbContext 的配置连接字符串、Provider、日志开关等应通过构造函数注入DbContextOptionsTContext而不是在OnConfiguring里硬编码。重写 OnModelCreating 进行 Fluent API 配置Override OnModelCreating for fluent API configuration模型的核心映射逻辑集中放在OnModelCreating中完成。使用 IEntityTypeConfiguration 分离实体配置Separate entity configurations using IEntityTypeConfiguration当实体较多时为每个实体创建独立的IEntityTypeConfigurationTEntity实现类并在OnModelCreating中通过modelBuilder.ApplyConfigurationsFromAssembly(typeof(YourContext).Assembly)一次性加载避免OnModelCreating无限膨胀。考虑在控制台应用或测试中使用 DbContextFactory 模式Consider using DbContextFactory pattern for console apps or tests通过AddDbContextFactoryTContext()注册工厂按需创建短生命周期的上下文实例这是控制台应用与测试环境下的推荐做法。从源码佐证角度看仓库中的 efcore-d2-db-diagram 技能在分析 EF Core 代码库时给出了严格的文件检查顺序与映射优先级与上述设计要点相互印证优先检查DbContext类检查DbSetT声明检查OnModelCreating检查IEntityTypeConfigurationT配置类检查实体类检查迁移与模型快照model snapshot检查数据注解Data Annotations。其 efcore-model-extraction.md 进一步明确了映射来源冲突时的优先级最新迁移 / 模型快照已落库的事实Fluent APIOnModelCreating与IEntityTypeConfigurationT数据注解EF Core 约定conventions原始 C# 类形状。这提醒我们IEntityTypeConfiguration之所以是推荐的配置载体不仅因为它让代码更整洁还因为 Fluent API 的优先级高于数据注解与约定——它是决定数据库真实长什么样的关键层理应被清晰、集中地管理。三、Entity Design主键、关系、导航属性与值对象原文档在实体设计维度的实践要点使用有意义的主键权衡自然键与代理键Use meaningful primary keys, consider natural vs surrogate keys自然键如身份证号有业务含义但易变、易过长代理键自增/Guid稳定但与业务解耦。需根据业务稳定性、索引体积与并发场景权衡。实现正确的关系类型Implement proper relationships: one-to-one, one-to-many, many-to-many通过导航属性 外键属性的组合表达关系避免仅靠裸外键拼图。使用数据注解或 Fluent API 声明约束与验证Use data annotations or fluent API for constraints and validations如[Required]、[MaxLength(50)]、HasMaxLength、IsRequired等让约束在数据库层同步生效。实现恰当的导航属性Implement appropriate navigational properties区分集合导航ICollectionT与引用导航并保持两端一致性。考虑用 owned entity types 建模值对象Consider using owned entity types for value objects值对象如Address、Money应使用OwnsOne/OwnsMany或[Owned]内嵌到实体中而非作为独立实体表存在。仓库中 efcore-model-extraction.md 列出了模型提取时需要重点检测的 EF Core API 清单恰好覆盖了实体设计的全部关键映射点ToTable、HasKey、HasAlternateKey、HasIndex、IsUnique、Property、HasColumnName、HasColumnType、IsRequired、HasMaxLength、HasConversion、HasOne、WithMany、WithOne、HasForeignKey、OnDelete、OwnsOne、OwnsMany、UsingEntity、Ignore。其中几个要点值得展开HasAlternateKey用于声明备用键如唯一业务号它既能在数据库生成唯一约束也是 EF Core 识别按备用键关联的依据。HasConversion值转换器用于将复杂类型映射为数据库列类型如把枚举存为字符串、把DateTimeOffset转成long是值对象落库的核心手段。UsingEntity用于显式配置多对多关系的联接表join table。OnDelete控制删除行为Cascade、Restrict、NoAction、SetNull、ClientSetNull直接影响数据库外键约束与级联删除语义。四、Performance查询性能的六条军规性能是 EF Core 实践中最常被诟病的领域原文档给出的六条核心实践只读查询使用 AsNoTracking()UseAsNoTracking()for read-only queries关闭变更跟踪显著降低内存占用与快照比较开销。若查询结果不会被修改并SaveChanges()一律优先AsNoTracking()。对大结果集使用 Skip() Take() 分页Implement pagination for large result sets withSkip()andTake()把分页下推到数据库执行避免全表加载。更进阶的方案是键集分页keyset pagination基于Where(x x.Id lastId)在大数据量下比Skip/Take的偏移分页更稳定。需要时用 Include() 预加载关联实体UseInclude()to eager load related entities when needed预加载在一条 SQL或少量 SQL中取回关联数据。考虑用投影Select只取所需字段Consider projection (Select) to retrieve only required fieldsSelect(x new { x.Id, x.Name })只查询需要的列减少传输与实体物化开销。对高频执行查询使用编译查询Use compiled queries for frequently executed queries通过EF.CompileQuery或EF.CompileAsyncQuery预编译查询缓存翻译结果避免每次执行都重新编译表达式树。通过正确预加载关联数据避免 N1 问题Avoid N1 query problems by properly including related dataN1 即先查 1 条主记录再为每条主记录各发 1 条关联查询是性能杀手。Include/ThenInclude预加载、投影或拆分查询AsSplitQuery都能缓解。需要特别指出的是性能优化与变更跟踪的联动关系只读投影 AsNoTracking意味着实体不进入跟踪图后续若需要更新应通过显式加载Find/First重新查询或附加Attach的方式再纳入跟踪这正是选择合适的变更跟踪策略见第六节的体现。五、Migrations小而聚焦、可验证、可部署的迁移管理原文档的迁移实践要点创建小而聚焦的迁移Create small, focused migrations一次迁移只表达一个逻辑变更如新增 Order 表或给 Customer 表加索引便于评审、回滚与定位问题。为迁移起描述性名称Name migrations descriptivelyAddCustomerEmailIndex比Migration2更有意义dotnet ef migrations add AddCustomerEmailIndex生成的迁移类名与文件名都能直接表达意图。在应用到生产环境前验证迁移 SQL 脚本Verify migration SQL scripts before applying to production通过dotnet ef migrations script生成迁移 SQL 并人工/自动评审。考虑使用迁移包migration bundles进行部署Consider using migration bundles for deploymentdotnet ef migrations bundle可生成自包含的可执行文件无需在目标环境安装 EF 工具适合 CI/CD 流水线。通过迁移进行数据种子seedingAdd data seeding through migrations when appropriate配置类中的种子数据HasData会被纳入迁移适合基础字典数据的初始化。仓库的 efcore-d2-db-diagram 技能把迁移定位为判断数据库模型事实的最高优先级证据Latest applied migration / migration snapshot 高于 Fluent API 与数据注解。其原因在于迁移是 EF Core 对目标数据库实际执行了什么的忠实记录从迁移中可以确认真实的表名ToTable生效后的结果与 schema 名多对多关系产生的联接表影子外键列shadow FK columns索引与唯一约束复合主键删除行为仅存在于迁移、没有对应实体的表migration-only tables如__EFMigrationsHistory。这意味着迁移不仅是部署工具更是模型的事实来源source of truth。评审 EF Core 代码时若实体配置与最新迁移冲突应以迁移为准。此外该技能还提示技术表如__EFMigrationsHistory、Hangfire 表、ASP.NET Identity 表、审计日志、Outbox 表通常在 ERD 中默认隐藏——这与小而聚焦的迁移 清晰的数据库全景的治理思路一致。六、Querying可组合、可复用、可下推的查询设计原文档的查询实践要点审慎使用 IQueryable并理解查询何时真正执行UseIQueryablejudiciously and understand when queries executeIQueryable是可组合的查询描述直到ToList()/First()/Count()/AsAsyncEnumerable()等终端操作才真正触发数据库执行。误用IQueryable如长链式组合导致查询翻译爆炸或在内存中重复枚举同一IQueryable是常见陷阱。优先使用强类型 LINQ 而非裸 SQLPrefer strongly-typed LINQ queries over raw SQL强类型 LINQ 提供编译期检查与可组合性且天然参数化。使用恰当的查询操作符Use appropriate query operators:Where,OrderBy,GroupBy确保这些操作尽可能在数据库侧执行查询下推避免Enumerable在内存中兜底。考虑用数据库函数处理复杂操作Consider database functions for complex operations如EF.Functions.Like、Contains翻译为LIKE/IN或通过HasDbFunction映射自定义数据库函数。用规范模式Specification Pattern实现可复用查询Implement specifications pattern for reusable queries把可复用的过滤/排序条件封装为 Specification 对象结合Include表达式组合避免在业务层重复拼装查询逻辑。七、Change Tracking Saving跟踪策略、批量保存与并发控制原文档在变更跟踪与保存维度的实践要点使用恰当的变更跟踪策略Use appropriate change tracking strategies读多改少的场景用AsNoTracking()需要更新的场景确保实体被正确跟踪查询后跟踪、Attach 属性标记Modified、或显式Update。批量调用 SaveChanges()Batch yourSaveChanges()calls将一批相关变更集中为一次SaveChanges()一方面让 EF Core 把多条插入/更新合并为批量语句EF Core 7 的SaveChanges批量更新另一方面避免每写一条就提交一次事务性往返。为多用户场景实现并发控制Implement concurrency control for multi-user scenarios在实体上配置并发令牌IsConcurrencyToken或[Timestamp]行版本列当并发冲突时由DbUpdateConcurrencyException触发冲突处理。多个操作考虑使用事务Consider using transactions for multiple operations默认SaveChanges()自身即在一个事务中跨多次SaveChanges()或多个DbContext的操作应显式使用Database.BeginTransaction()或TransactionScope保证原子性。使用恰当的 DbContext 生命周期Use appropriate DbContext lifetimes, scoped for web appsWeb 应用中 DbContext 默认注册为Scoped每请求一个实例避免长时间存活导致的跟踪图膨胀与过期缓存这与 dotnet-best-practices 中以合适生命周期注册服务Singleton/Scoped/Transient的建议保持一致。八、Security参数化、权限与敏感数据处理原文档的安全实践要点使用参数化查询避免 SQL 注入Avoid SQL injection by using parameterized queries所有通过 LINQ 生成的 SQL 天然参数化即使使用FromSqlRaw也务必使用占位符传参如FromSqlRaw(SELECT * FROM Users WHERE Id {0}, id)严禁字符串拼接用户输入。实现恰当的数据访问权限Implement appropriate data access permissions数据库账号遵循最小权限原则应用层配合数据行级过滤如全局查询过滤器HasQueryFilter实现多租户/软删除。谨慎使用原生 SQL 查询Be careful with raw SQL queriesFromSqlRaw/ExecuteSqlRaw只应在 LINQ 无法表达的边缘场景使用且必须参数化。考虑对敏感信息进行数据加密Consider data encryption for sensitive information敏感列可结合值转换器HasConversion与对称加密算法实现列级加密或依赖数据库透明加密。使用迁移管理数据库用户权限Use migrations to manage database user permissions将授权语句GRANT/REVOKE纳入迁移脚本使权限变更与模型变更同源、可评审、可回滚。九、Testing内存库、SQLite 与快照测试的组合策略原文档的测试实践要点单元测试使用 InMemory 数据库提供程序Use in-memory database provider for unit testsUseInMemoryDatabase适合验证查询/仓储逻辑的正确性但它不模拟真实 SQL 语义如关系约束、事务、类型转换因此仅限快速单元测试。集成测试使用 SQLite 创建独立测试上下文Create separate testing contexts with SQLite for integration testsUseSqlite(DataSource:memory:)能真实执行 SQL 翻译与关系约束比 InMemory 更接近生产行为且无需真实数据库服务。纯单元测试 Mock DbContext 与 DbSetMock DbContext and DbSet for pure unit tests借助 Moq仓库 dotnet-best-practices 技能同样推荐 Moq 作为 Mock 框架模拟DbSetT返回内存数据隔离被测逻辑。在隔离环境测试迁移Test migrations in isolated environments在 CI 中针对空数据库按序执行全部迁移验证脚本可重放、无缺漏。考虑对模型变更做快照测试Consider snapshot testing for model changesEF Core 本身维护ModelSnapshotMigrations/YourContextModelSnapshot.cs对模型变更进行基于快照的回归校验确保任何模型调整都产生预期迁移。十、配套资源从最佳实践到数据库模型可视化ef-core技能聚焦如何写得更好而仓库中的 efcore-d2-db-diagram 技能则聚焦如何把写出来的模型看清楚——两者构成完整的 EF Core 开发闭环。该技能的核心流程是读取 EF Core 项目结构定位所有DbContext与DbSetT分析OnModelCreating与全部IEntityTypeConfigurationT结合迁移确认表名、联接表、索引与删除行为归一化数据库模型后生成.d2文件用d2CLI 渲染为 SVG/PNG如d2 --layoutelk schema.d2 schema.svg。其生成的 ERD 要求如实反映 EF Core 持久化模型主外键、owned types 与值对象、多对多联接表、索引与唯一约束、影子列、值转换后的列类型等均需在图中体现——这正是对本文第三、五节实体设计与迁移实践的可视化验证。同时该技能在交付前有一份质量门禁清单Quality Gate例如所有DbSetT实体是否均已考虑、表名与 schema 是否与 EF Core 映射一致、主外键与基数是否已表示、隐藏的技术表是否在摘要中列出。这套清单也可以反过来作为 EF Core 代码评审的检查项。结语把最佳实践固化为可执行的评审标准skills/ef-core/SKILL.md的精髓在于把散落在社区与官方文档中的 EF Core 经验浓缩为一份 Copilot 可直接执行的评审清单。当你在 Copilot 中启用该技能并粘贴代码时它会按这八个维度逐项检查并提出改进建议。配合仓库中的 efcore-d2-db-diagram模型可视化、dotnet-best-practices.NET 全局规范以及 csharp-dotnet-development 插件你可以获得从数据访问层到整个 .NET 解决方案的完整质量保障。将本文梳理的清单作为日常评审基线是降低 EF Core 项目长期维护成本最直接有效的方式。【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考