2012-06-02 81 views
6

對於精通EF的用戶來說,這應該是一個簡單的問題。映射多對多關係(帶外鍵參考)

我有以下架構(在我的腦海中)表格之間的關係應該看起來如何。

[FooBar]  [Foo]   [Bar] 

FooId PK,FK Id PK   Id PK 
BarId PK,FK BarId FK  Name 
IsRead  Name   Description 
       Description  

不過,當我嘗試使用EF代碼首先它不能解釋,因爲我已經作出瞭解釋實體之間的關係產生模式(增加了外鍵FooId[bar]表)和失敗完全創建[FooBar]橋表。

如果有人能指導我如何使用EF4代碼實現上述架構 - 首先,我會很感激。無論解決方案是否包含我的POCO模型中的屬性,流利配置或兩者的混合都無關緊要 - 只要創建了所需的數據庫模式即可。


POCO模式:

public class Foo 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 
    public int BarId { get; set; } 

    public Bar Bar { get; set; } /* bar entity */ 

    public virtual ICollection<Bar> BridgedBars { get; set; } 

    public Foo() 
    { 
     Bars = new List<Bar>(); 
    } 
} 

public class Bar 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 

    public virtual ICollection<Foo> Foos { get; set; } 
    public virtual ICollection<Foo> BridgedFoos { get; set; } 

    public Bar() 
    { 
     Foos = new List<Foo>(); 
     BridgedFoos = new List<Foo>(); 
    } 
} 

public class FooBar 
{ 
    public int FooId { get; set; } 
    public int BarId { get; set; } 

    public virtual Foo Foo { get; set; } 
    public virtual Bar Bar { get; set; } 

    public bool IsRead { get; set; } 
} 
+0

正如你有一個關於FooBar關係的屬性(IsRead),您可能想從代碼中設置,Foo和Bar都需要它們的相關集合爲FooBars。一旦將兩端的屬性(即Foo和Bar中的虛擬集合)映射到FooBar EF,應該正確地創建關係。使用HasMany()。WithRequired()將每個類映射到FooBar。 –

回答

8

您的模型確實會創造一種屬於由Foo.BrideBars定義的關係Bar外鍵FooId。 EF未將此導航屬性與Bar中的ICollection<Foo>屬性之一關聯,因爲其中有兩個,而EF無法唯一確定哪個是正確的對。因此,它爲Foo.BrideBars創建了一個關係,而在另一端沒有導航屬性。可以這麼說,有一個不可見的Bar.Foo屬性會導致外鍵。

要映射到模型的數據庫模式並不真正代表多對多關係,而是代表與中間「橋」實體FooBar的兩個一對多關係。您必須在導航屬性中使用此類來定義正確的關係。它看起來像這樣:

public class Foo 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 

    public int BarId { get; set; } 
    public Bar Bar { get; set; } 

    public virtual ICollection<FooBar> FooBars { get; set; } 
} 

public class Bar 
{ 
    public int Id { get; set; } 
    public string Text { get; set; } 
    public string Description { get; set; } 

    public virtual ICollection<Foo> Foos { get; set; } 
    public virtual ICollection<FooBar> FooBars { get; set; } 

} 

public class FooBar 
{ 
    [Key, Column(Order = 0)] 
    public int FooId { get; set; } 
    [Key, Column(Order = 1)] 
    public int BarId { get; set; } 

    public virtual Foo Foo { get; set; } 
    public virtual Bar Bar { get; set; } 

    public bool IsRead { get; set; } 
} 

正確的關係將通過此模型中的命名約定檢測到。僅用於FooBar實體,因爲屬性名稱不符合約定(沒有IdFooBarId屬性),所以有必要明確定義一個鍵。在這個模型中,在FooBar中使用複合鍵是有意義的。

我想,你的真實課程和屬性沒有名字FooBar。如果您的真實姓名不遵守約定,你可能必須與批註中指定的關係 - 或者用流利的API:

modelBuilder.Entity<Foo>() 
    .HasRequired(f => f.Bar) 
    .WithMany(b => b.Foos) 
    .HasForeignKey(f => f.BarId); 

modelBuilder.Entity<FooBar>() 
    .HasKey(fb => new { fb.FooId, fb.BarId }); // replaces the [Key] annotations 

modelBuilder.Entity<FooBar>() 
    .HasRequired(fb => fb.Foo) 
    .WithMany(f => f.FooBars) 
    .HasForeignKey(fb => fb.FooId); 

modelBuilder.Entity<FooBar>() 
    .HasRequired(fb => fb.Bar) 
    .WithMany(b => b.FooBars) 
    .HasForeignKey(fb => fb.BarId); 

在你的數據庫模式FooBar表有一個複合主鍵:

[FooBar]  [Foo]   [Bar] 

FooId PK,FK Id PK   Id PK 
BarId PK,FK BarId FK  Name 
IsRead   Name   Description 
       Description  

但是在FooBar中有一個PK是必要的,因爲EF模型中的每個實體都必須具有定義的鍵屬性 - 單個或複合 - 映射到數據庫表中的主鍵。

在這個問題 - Create code first, many to many, with additional fields in association table - 更多的細節如何使用這種類型的關係。 (有時人們也稱它爲「多對一對多的關係與有效載荷」(以下IsRead屬性是你的榜樣模型中的「有效載荷」),但實際上它不是多到很多。)

+0

究竟是我在找什麼,而且在'FooBar'上有一個複合主鍵是我的意圖 - 只是忘了提及它!感謝您的好評和解釋!一旦我的個人資料達到* 15分*我一定會回來和投票。 – culturalanomoly