2015-09-19 137 views
1

我有DB實體Item可以鏈接到其他項目(相同的實體)。理想狀態是有Item類一個收集:實體框架對稱多對多關係

public class Item 
{ 
    public virtual ICollection<Item> LinkedItems { get; set; } 
} 

的關係是對稱的,所以如果itemA鏈接到itemB它會自動意味着itemB鏈接到itemA

我有以下兩種方法:

  1. 有一個LinkedItems財產,每次上這兩個項目增加:

    itemA.LinkedItems.Add(itemB); 
    itemB.LinkedItems.Add(itemA); 
    
  2. 有兩個屬性LinkedItems1LinkedItems2,每次Concat的他們:

    var linkedItems = itemA.LinkedItems.Concat(itemB.LinkedItems); 
    

上述方法都不是理想的。它可以做得更好(更清潔)嗎?

我正在使用EF Code First。

回答

0

對你而言,Item應該有2個導航屬性。一個用於鏈接的項目,另一個用於鏈接的項目。

public class Item 
{ 
    public virtual ICollection<ItemAssociation> AssociatedItems { get; set; } 
    public virtual ICollection<ItemAssociation> ItemsAssociatedThisItem { get; set; } 
} 

public class ItemAssociation 
{ 
    public int ItemId { get; set; } 

    public int ItemAssociatedId { get; set; } 

    public virtual Item Item { get; set; } 

    public virtual Item ItemAssociated { get; set; } 
} 

映射:

modelBuilder.Entity<ItemAssociation>() 
     .HasKey(i => new {i.ItemId , i.ItemAssociatedId }); 

    modelBuilder.Entity<Item>() 
     .HasMany(i => i.AssociatedItems) 
     .WithRequired(i => i.ItemAssociated) 
     .HasForeignKey(i => i.ItemAssociatedId) 
     .WillCascadeOnDelete(false); 

    modelBuilder.Entity<Item>() 
     .HasMany(i => i.ItemsAssociatedThisItem) 
     .WithRequired(i => i.Item) 
     .HasForeignKey(i => i.ItemId) 
     .WillCascadeOnDelete(false); 

當你想要檢索與特定項目的所有項目,你會得到兩個集合,CONCAT他們並刪除重複值。

EDIT

無關聯實體映射:

類別:

public class Item 
{ 
    public int ItemId { get; set; } 

    public virtual ICollection<Item> AssociatedItems { get; set; } 
    public virtual ICollection<Item> ItemsAssociatedThisItem { get; set; } 
} 

映射:

modelBuilder.Entity<Item>() 
    .HasMany(i => i.AssociatedItems) 
    .WithMany(i=> i.ItemsAssociatedThisItem) 
    .Map(i => 
     { 
      i.MapRightKey("ItemId"); 
      i.MapLeftKey("AssociatedItemId"); 
      i.ToTable("ItemsAssociation"); 
     }); 

生成遷移:

CreateTable(
    "dbo.Items", 
    c => new 
     { 
      ItemId = c.Int(nullable: false, identity: true), 
     }) 
    .PrimaryKey(t => t.ItemId); 

CreateTable(
    "dbo.ItemsAssociation", 
    c => new 
     { 
      AssociatedItemId = c.Int(nullable: false), 
      ItemId = c.Int(nullable: false), 
     }) 
    .PrimaryKey(t => new { t.AssociatedItemId, t.ItemId }) 
    .ForeignKey("dbo.Items", t => t.AssociatedItemId) 
    .ForeignKey("dbo.Items", t => t.ItemId) 
    .Index(t => t.AssociatedItemId) 
    .Index(t => t.ItemId); 

我覺得現在比較乾淨。只是根據你的風格改變名稱

+0

添加一個關聯實體根本不能解決問題,這讓我覺得它更加複雜。 –

+0

一個'Item'可以鏈接到多個'Item',對吧?項目A鏈接到B和C.項目B鏈接到D和A(由於前面的鏈接)。所以,我相信唯一可以做到這一點的方法是使用關聯實體。另外,要做出「反身關係」,實體需要2個集合......每個集合都有一個集合。看看這個線程,它可能是有用的http://stackoverflow.com/questions/31461173/entity-framework-fluent-api-create-table-with-2-fk/31465908#31465908 –

+0

你正在描述古典很多我熟悉的很多關係。我提出的用例在邏輯上只需要一個集合,問題在於是否可以用EF完成一個集合。 並且不,您不必爲多對多關係設置關聯實體。 EF可以爲你做這件事 - 當然在數據庫中會有一個關聯表,但它會隱藏在模型中。 –