2012-11-09 77 views
12

我使用實體框架代碼優先自動創建我的數據庫架構,和我的實體的一個看起來是這樣的:爲什麼EF代碼首先生成一個無關的外鍵列?

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不能再自動匹配CaseStudyICollection<AssessmentsCaseStudies>CaseStudyId列,因此它會創建自己的列以將這兩者鏈接在一起以獲取該導航屬性。

+0

我真的不明白這個問題的接受答案。我在'AssessmentsCaseStudies'中有兩個'CaseStudy'參考,所以我沒有真正的多對多關係,我不明白爲什麼我需要一個聯結表。我確實有'public virtual ICollection AssessmentsCaseStudies {get;組; }'''CaseStudy'中,所以我想要說一說ICollection應該與'CaseStudyId' FK相關,而不是'FollowsCaseStudyId' FK。 – Jez

+0

好的,我認爲它可能包含有用的信息。你可以嘗試創建一個精簡的例子,例如只有一個'Assessment','CaseStudy'和'AssesmentCaseStudy'實體,每個實體只包含一個'ID'字段和'AssesmentCaseStudy'包含一個'AssesmentID'和一個'CaseStudyID '領域?問題是否仍然存在? – CodeCaster

+1

我不認爲這個問題應該被關閉,因爲接受的「重複」問題的答案沒有解釋得很好,我想要一個更好的答案。請投票重新開放。 – Jez

回答

7

由於某種原因,Slauma的InverseProperty屬性建議不起作用。什麼做的工作是我定兩條CaseStudy導航屬性之間AssessmentsCaseStudiesCaseStudy實體之間的關係,通過流暢API在我的數據庫上下文的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); 

一旦這樣補充,這是時產生的遷移代碼I Add-Migration不再試圖添加CaseStudy_CaseStudyId列,而只是添加了FollowsCaseStudyId列,並添加了適當的外鍵關係。

+0

你有'InverseProperty'異常屬性還是你還有第三個FK?它應該工作。它與Fluent映射完全相同 - 只有一個例外:該屬性不會禁用第一個關係的級聯刪除(因爲第二個級聯刪除是默認關閉的,因爲它是可選關係)。 – Slauma

+0

它仍然創建了第三個FK。 – Jez

16

因爲你有你的AssessmentsCaseStudies實體在CaseStudy實體CaseStudy類型的導航性能和AssessmentsCaseStudies收集EF不能決定哪兩個CaseStudy導航屬性的這個集合指。兩者都是可能的,兩個選項都會導致一個有效但不同的實體模型和數據庫模式。

在這樣一個模棱兩可的情況EF約定是實際創建關係,即您的收藏CaseStudy不涉及任何兩個CaseStudy導航性質的,但有三分之一(但不暴露和「隱形」)終點在AssessmentsCaseStudies。這第三種關係是你在數據庫中看到的第三個外鍵的原因 - 帶下劃線的那個。 (下劃線始終是一個強有力的跡象表明,一些通過映射慣例,而不是由您明確配置或數據註解happend。)

要解決此問題,並覆蓋您可以將[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; } 
+0

我正在處理類似的事情 - 我嘗試了你的建議,但得到了一個異常。如果你有一分鐘​​:http://stackoverflow.com/questions/19802324/why-is-this-column-getting-generated-in-ef-code-first-migrations – RobVious

0

對於在這裏尋找解決方案的其他人,如果您嘗試了以前的答案並仍在獲得額外的外鍵列,請查找您可能已定義的POCO類的更多屬性,而您並不打算映射到數據庫字段。即使它們包含代碼塊,與複雜的get訪問器一樣,實體框架也會試圖以某種方式將它們映射到數據庫。如果您的屬性返回實體,這可能會導致額外的外鍵列。爲了安全起見,請使用[NotMapped]屬性修飾這些屬性或將它們轉換爲方法。