EF Core 6脚手架跳过多引用表外键的问题及解决诉求
问题描述
将应用从.NET 5(搭配EF Core 5)迁移至.NET 6(搭配EF Core 6)后,使用脚手架生成数据库上下文时遇到如下问题:
数据库内有一张翻译表Translation,用于存储动态数据的译文。部分表(如Hazmat)包含多个关联翻译表主键的列(TranslationKeyName对应名称翻译、TranslationKeyDescription对应描述翻译)。
- EF Core 5的脚手架可生成正确的多导航属性代码(命名虽不规范,但关联关系正确):
public partial class Translation { ... public virtual Hazmat TranslationKey12 { get; set; } public virtual Hazmat TranslationKey15 { get; set; } ... } public partial class Hazmat { public Hazmat() { TranslationTranslationKey12s = new HashSet<Translation>(); TranslationTranslationKey15s = new HashSet<Translation>(); } public Guid TranslationKeyName { get; set; } public Guid TranslationKeyDescription { get; set; } public virtual ICollection<Translation> TranslationTranslationKey12s { get; set; } public virtual ICollection<Translation> TranslationTranslationKey15s { get; set; } }
- EF Core 6的脚手架则会抛出警告:Skipping foreign key 'FK_Translation_HazmatName' on table 'Application.Translation' since it is a duplicate of 'FK_Translation_HazmatDescription',并仅生成单个导航属性,错误将两个外键判定为同一关联:
public partial class Translation { ... public virtual Hazmat TranslationKey12 { get; set; } ... } public partial class Hazmat { public Hazmat() { Translations = new HashSet<Translation>(); } public Guid TranslationKeyName { get; set; } public Guid TranslationKeyDescription { get; set; } public virtual ICollection<Translation> Translations { get; set; } }
解决方案
目前无法直接恢复EF Core 5的脚手架生成行为,但可以通过以下两种方式修正关联关系:
1. 手动修正生成的实体类与上下文配置
这是最直接可靠的方式:
- 在
Translation类中添加缺失的导航属性:
public partial class Translation { ... // 对应Hazmat的TranslationKeyName列 public virtual Hazmat HazmatName { get; set; } // 对应Hazmat的TranslationKeyDescription列 public virtual Hazmat HazmatDescription { get; set; } ... }
- 在
Hazmat类中添加对应的集合导航属性:
public partial class Hazmat { public Hazmat() { TranslationKeyNameTranslations = new HashSet<Translation>(); TranslationKeyDescriptionTranslations = new HashSet<Translation>(); } public Guid TranslationKeyName { get; set; } public Guid TranslationKeyDescription { get; set; } public virtual ICollection<Translation> TranslationKeyNameTranslations { get; set; } public virtual ICollection<Translation> TranslationKeyDescriptionTranslations { get; set; } }
- 在DbContext的
OnModelCreating方法中,使用Fluent API明确配置两个外键关联:
protected override void OnModelCreating(ModelBuilder modelBuilder) { ... // 配置Translation与Hazmat的TranslationKeyName关联 modelBuilder.Entity<Translation>() .HasOne(t => t.HazmatName) .WithMany(h => h.TranslationKeyNameTranslations) .HasForeignKey("<Translation表中对应HazmatName的外键列名>") // 替换为实际列名,如HazmatNameId .HasPrincipalKey(h => h.TranslationKeyName) .OnDelete(DeleteBehavior.Restrict); // 根据业务需求设置删除行为 // 配置Translation与Hazmat的TranslationKeyDescription关联 modelBuilder.Entity<Translation>() .HasOne(t => t.HazmatDescription) .WithMany(h => h.TranslationKeyDescriptionTranslations) .HasForeignKey("<Translation表中对应HazmatDescription的外键列名>") // 替换为实际列名,如HazmatDescriptionId .HasPrincipalKey(h => h.TranslationKeyDescription) .OnDelete(DeleteBehavior.Restrict); ... }
2. 使用脚手架参数优化生成结果
尝试在执行脚手架命令时添加--use-database-names参数,让脚手架保留数据库原生的列名和外键命名,可能帮助其正确识别不同的关联关系:
dotnet ef dbcontext scaffold "YourConnectionString" Microsoft.EntityFrameworkCore.SqlServer --use-database-names
不过这种方式不一定能完全解决问题,最终可能仍需手动调整部分配置。
内容的提问来源于stack exchange,提问作者Skuami
相关产品推荐
相关产品推荐

