C# 为什么EF代码首先生成一个无关的外键列?
我首先使用实体框架代码自动创建数据库模式,其中一个实体如下所示:C# 为什么EF代码首先生成一个无关的外键列?,c#,database,entity-framework,ef-code-first,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(Or
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\u CaseStudyId
列之外,这一切都很好。为什么会产生这种情况?这是干什么用的?我怎样才能阻止它的生成?我怀疑EF不能再自动将CaseStudy
的ICollection
与CaseStudyId
列匹配,因此,它创建了自己的列,将这两个导航属性链接在一起。因为在评估评估评估研究
实体中有两个类型的案例研究
导航属性,而在案例研究
实体中有一个评估评估评估研究
集合,EF无法决定是哪一个此集合引用的两个案例研究中的导航属性。两者都是可能的,并且这两个选项都会产生一个有效但不同的实体模型和数据库模式
在这种模棱两可的情况下,EF惯例是创建实际的三个关系,即案例研究中的集合不引用两个案例研究
导航属性中的任何一个,但在评估研究
中有第三个端点(但不公开和“不可见”)。这第三个关系是您在数据库中看到的第三个外键的原因—带下划线的外键。(下划线始终是通过映射约定而不是通过显式配置或数据注释发生事情的强烈指示。)
要解决问题并覆盖约定,您可以应用[InverseProperty]
属性,从而指定案例研究
导航属性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; }
[InverseProperty(“案例研究”)]//评估案例研究实体中的案例研究属性
公共虚拟ICollection assessmentsCasStudies{get;set;}
出于某种原因,Slauma的反向属性建议不起作用。我所做的工作是通过数据库上下文的OnModelCreating
方法中的Fluent API指定案例研究
导航属性和案例研究
实体之间的关系:
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);
modelBuilder.Entity()
.HasRequired(acs=>acs.案例研究)
.有许多(cs=>cs.评估研究)
.HasForeignKey(acs=>acs.CaseStudyId)
.WillCascadeOnDelete(假);
modelBuilder.Entity()
.has可选(acs=>acs.Follows)
.WithMany()//无反向导航属性
.HasForeignKey(acs=>acs.followsCaseStudio)
.WillCascadeOnDelete(假);
添加后,当我添加迁移时生成的迁移代码不再尝试添加CaseStudy\u CaseStudyId
列,我只添加了FollowsCaseStudyId
列,并添加了相应的外键关系。对于任何登陆此处寻找解决方案的人,如果您已经尝试了前面的答案,但仍然得到了一个额外的外键列,请查找您可能在POCO类下定义的、不打算映射到DB字段的任何属性。即使它们包含代码块,就像复杂的get访问器一样,实体框架也会尝试以某种方式将它们映射到数据库。如果属性返回实体,这可能会导致额外的外键列。为了安全起见,要么用[NotMapped]
属性装饰这些属性,要么将它们转换为方法。我真的不明白这个问题的公认答案。我在评估研究
中正好有两个案例研究
参考资料,因此我没有真正的多对多关系,也不明白为什么我需要一个连接表。不过,我在案例研究
中确实有公共虚拟ICollection评估研究{get;set;}
,所以我想说,ICollection应该与案例研究ID
FK相关,而不是FollowsCaseStudyId
FK。好的,我认为它可能包含有用的信息。您是否可以尝试创建一个精简的示例,例如,仅使用评估
、案例研究
和评估案例研究
实体,每个实体仅包含一个ID
字段,而评估案例研究
包含一个评估ID
和一个案例研究ID
字段?这个问题还会发生吗?我不认为这个问题应该结束,因为对“被骗”问题的公认答案不能很好地解释问题,我想要一个更好的答案。请投票重新打开。您是否因InverseProperty
属性而出现异常,或者您是否仍有第三个FK?这本应该奏效的。它与Fluent映射的作用相同-只有一个例外:该属性没有为第一个关系禁用级联删除(因为第二个级联删除是可选关系,所以默认情况下处于禁用状态)。它仍然创建了第三个FK。我正在处理类似的问题-我尝试了你的建议,但遇到了一个异常。如果你有时间: