为什么EF代码首先生成一个无关的外键列?

我正在使用entity framework代码 – 首先自动创建我的数据库模式,我的一个实体看起来像这样:

public class AssessmentsCaseStudies { #region Persisted fields [Required] [Key, Column(Order=0)] [ForeignKey("Assessment")] public int AssessmentId { get; set; } [Required] [Key, Column(Order=1)] [ForeignKey("CaseStudy")] public int CaseStudyId { get; set; } [Required] public int Score { get; set; } [ForeignKey("Follows")] public int? FollowsCaseStudyId { get; set; } #endregion #region Navigation properties public virtual Assessment Assessment { get; set; } public virtual CaseStudy CaseStudy { get; set; } public virtual CaseStudy Follows { get; set; } #endregion } 

当EF自动生成我的数据库时,它会生成一个包含以下列的表:

 AssessmentId (PK, FK, int, not null) CaseStudyId (PK, FK, int, not null) Score (int, not null) FollowsCaseStudyId (FK, int, null) CaseStudy_CaseStudyId (FK, int, null) 

除了CaseStudy_CaseStudyId列之外,这一切都很好。 为什么会产生这个? 它是为了什么? 如何阻止它生成? 我怀疑EF不能再自动将CaseStudyICollectionCaseStudyId列匹配,因此它创建了自己的列来将两者链接在一起以获得该导航属性。

由于您的AssessmentsCaseStudies实体中有两个类型为CaseStudy导航属性,而CaseStudy实体中有一个AssessmentsCaseStudies集合,因此EF无法决定此集合引用的两个CaseStudy导航属性中的哪一个。 两者都是可能的,两个选项都会产生有效但不同的实体模型和数据库模式。

在这种模糊的情况下,EF惯例是实际创建三个关系,即CaseStudy中的集合不引用两个CaseStudy导航属性中的任何一个,但在AssessmentsCaseStudies具有第三个(但未暴露且“不可见”)端点。 第三个关系是你在数据库中看到的第三个外键的原因 – 带有下划线的那个。 (下划线总是强烈表明某些事情是通过映射约定而不是通过显式配置或数据注释发生的。)

要解决问题并覆盖约定,可以应用[InverseProperty]属性,从而指定AssessmentsCaseStudies集合所属的CaseStudy导航属性:

 [InverseProperty("AssessmentsCaseStudies")] // the collection in CaseStudy entity public virtual CaseStudy CaseStudy { get; set; } 

您也可以(或者,您不需要两者)将属性放在集合端:

 [InverseProperty("CaseStudy")] // the CaseStudy property in AssessmentsCaseStudies entity public virtual ICollection AssessmentsCaseStudies { get; set; } 

出于某种原因,Slauma的InverseProperty属性建议不起作用。 通过我的数据库上下文的OnModelCreating方法中的Fluent API,我在AssessmentsCaseStudiesCaseStudy实体中指定了两个CaseStudy导航属性之间的关系:

 modelBuilder.Entity() .HasRequired(acs => acs.CaseStudy) .WithMany(cs => cs.AssessmentsCaseStudies) .HasForeignKey(acs => acs.CaseStudyId) .WillCascadeOnDelete(false); modelBuilder.Entity() .HasOptional(acs => acs.Follows) .WithMany() // No reverse navigation property .HasForeignKey(acs => acs.FollowsCaseStudy) .WillCascadeOnDelete(false); 

添加后,我Add-Migration时生成的迁移代码不再尝试添加CaseStudy_CaseStudyId列,只是添加了FollowsCaseStudyId列,并具有适当的外键关系。

对于任何登陆此处寻找解决方案的人来说,如果您已尝试过以前的答案并且仍然获得额外的外键列,请查找您可能已在POCO类中进一步定义的任何您不打算映射到DB的属性领域。 即使它们包含代码块,与复杂的get访问器一样,Entity Framework也会尝试以某种方式将它们映射到数据库。 如果属性返回实体,这可能会导致额外的外键列。 为安全起见,要么使用[NotMapped]属性修饰此类属性,要么将它们转换为方法。