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

Jez*_*Jez 13 c# database entity-framework ef-code-first

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

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
}
Run Code Online (Sandbox Code Playgroud)

当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)
Run Code Online (Sandbox Code Playgroud)

除了CaseStudy_CaseStudyId专栏之外,这一切都很好.为什么会产生这个?它是为了什么?如何阻止它生成?我怀疑是EF可以不再自动匹配CaseStudyICollection<AssessmentsCaseStudies>CaseStudyId列,因此它会创建自己列两个为导航属性链接在一起.

Sla*_*uma 16

由于实体中有两个类型的导航属性,CaseStudyAssessmentsCaseStudies实体中有一个AssessmentsCaseStudies集合,因此CaseStudyEF无法决定CaseStudy此集合引用的两个导航属性中的哪一个.两者都是可能的,并且两个选项都将导致有效但不同的实体模型和数据库模式.

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

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

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

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

[InverseProperty("CaseStudy")] // the CaseStudy property in AssessmentsCaseStudies entity
public virtual ICollection<AssessmentsCaseStudies> AssessmentsCaseStudies { get; set; }
Run Code Online (Sandbox Code Playgroud)


Jez*_*Jez 7

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

modelBuilder.Entity<AssessmentsCaseStudies>()
    .HasRequired(acs => acs.CaseStudy)
    .WithMany(cs => cs.AssessmentsCaseStudies)
    .HasForeignKey(acs => acs.CaseStudyId)
    .WillCascadeOnDelete(false);

modelBuilder.Entity<AssessmentsCaseStudies>()
    .HasOptional(acs => acs.Follows)
    .WithMany()  // No reverse navigation property
    .HasForeignKey(acs => acs.FollowsCaseStudy)
    .WillCascadeOnDelete(false);
Run Code Online (Sandbox Code Playgroud)

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