2015-09-19 100 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可以为你做这件事 - 当然在数据库中会有一个关联表,但它会隐藏在模型中。 –