13

我使用实体框架代码优先自动创建我的数据库模式,我的一个实体如下所示:

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'sICollection<AssessmentsCaseStudies>CaseStudyId列,因此它创建自己的列来将两者链接在一起以用于该导航属性。

4

3 回答 3

15

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

在这种模棱两可的情况下,EF 约定实际上是创建三个关系,即您的集合 inCaseStudy不引用两个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; }
于 2012-11-10T19:15:53.737 回答
7

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

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添加了具有适当外键关系的列。

于 2012-11-11T15:08:56.263 回答
0

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

于 2017-01-18T20:12:06.030 回答