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

时间:2012-11-09 14:41:23

标签: 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
}

当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不能再自动将CaseStudy的{​​{1}}与ICollection<AssessmentsCaseStudies>列匹配,因此它会创建自己的列,将两者链接在一起以获取该导航属性。

3 个答案:

答案 0 :(得分:16)

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

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

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

[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> AssessmentsCaseStudies { get; set; }

答案 1 :(得分:7)

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

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);

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

答案 2 :(得分:0)

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