2016-12-26 124 views
0

我不知道如何在EF配置如下關係:實體框架建模一個一對多的關係

想象我需要創建一些語言詞典模型。我有一種語言和另一種語言的項目(例如單詞)。這兩個項目之間有一些關係。

例如:「洪德」(德國) - >「狗」(英文),關係型是「翻譯」

public enum Language 
{ 
    English, 
    German, 
} 

public class Item 
{ 
    public long ID { get; set; } 
    [Required] 
    public string Value { get; set; } 
    [Required] 
    public Language Language { get; set; } 

    public virtual ICollection<ItemRelation> ItemRelations { get; set; } 
} 

public enum ItemRelationType 
{ 
    Translate, 
    Synonym, 
} 

public class ItemRelation 
{ 
    public long ID { get; set; } 

    [ForeignKey("ItemID")] 
    public Item Item { get; set; } 

    [ForeignKey("RelativeItemID")] 
    public Item RelativeItem { get; set; } 

    [Required] 
    public ItemRelationType Type { get; set; } 
} 

EF標準遷移拋出一些錯誤在一種情況下,或創建列或FKS我不要(Item_ID等)在其他。

我想我需要配置一些流暢的API - 但我不知道我怎麼...

+0

「一些語言詞典模型」,「一些關係「,」一些錯誤「,」一個案例 - 另一個案例「 - 這些都很模糊。 –

回答

1

你缺少實際FK領域ItemIDRelativeItemID

,並配置您可以使用InverseProperty屬性,以禁用位EF公約沿導航性能(如下圖所示)。

public class ItemRelation 
{ 
    public long ID { get; set; } 

    public long ItemID { get; set; } // Missing 
    [ForeignKey("ItemID")] 
    [InverseProperty("ItemRelations")] 
    public virtual Item Item { get; set; } 

    public long RelativeItemID { get; set; } // Missing 
    [ForeignKey("RelativeItemID")] 
    [InverseProperty("RelativeItemRelations")] 
    public virtual Item RelativeItem { get; set; } 

    [Required] 
    public ItemRelationType Type { get; set; } 
} 

上述聲明使用virtual使延遲加載的作品。這是沒有必要的,你可以刪除它。結果是懶惰加載不起作用,這也沒關係。

假設你想爲你需要添加屬性的第二個關係的導航屬性:

public class Item 
{ 
... 
    public virtual ICollection<ItemRelation> RelativeItemRelations { get; set; } 
... 
} 

然後禁用級聯通過重寫OnModelCreating刪除慣例,如果您還沒有,在你的上下文類如下:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
... 
    modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
... 

這個解決方案應該工作,但它是有效地禁用級聯刪除所有一對多的關係。好處在於,您可以通過使用流暢的API逐案獲取它。

達到你想要的是隻使用流暢API如下第二種方法:

第二導航屬性添加到您的Item實體:

public class Item 
{ 
... 
    public virtual ICollection<ItemRelation> RelativeItemRelations { get; set; } 
... 
} 

ItemRelation實體缺少FKS,所以這裏是:

public class ItemRelation { public long ID {get;組; }用流利的API

public long ItemID { get; set; } // Missing 
    public virtual Item Item { get; set; } 

    public long RelativeItemID { get; set; } // Missing 
    public virtual Item RelativeItem { get; set; } 

    [Required] 
    public ItemRelationType Type { get; set; } 
} 

並配置導航屬性,避免級聯問題,你剛纔定義的關係:

public TheContext : DbContext 
{ 
    public DbSet<Item> Items { get; set; } 
    public DbSet<ItemRelation> ItemRelations { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Entity<ItemRelation>() 
       .HasRequired(e => e.Item) 
       .WithMany(t => t.ItemRelations) 
       .HasForeignKey(e => e.ItemID) 
       .WillCascadeOnDelete(false); 

     modelBuilder.Entity<ItemRelation>() 
       .HasRequired(e => e.RelatedItem) 
       .WithMany(t => t.RelativeItemRelations) 
       .HasForeignKey(e => e.RelativeItemID) 
       .WillCascadeOnDelete(false);  


     // Uncomment the following if you want to disable all cascading deletes and automatic fk creation conventions 
     // modelBuilder.Conventions.Remove<ForeignKeyIndexConvention>(); 
     // modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
     // modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); 

    ... 
    } 
} 

Read here for an opinion on why you might consider disabling those conventions.

+0

是的。但通過這種方式,我有以下錯誤:「在表'ItemRelations'上引入FOREIGN KEY約束'FK_dbo.ItemRelations_dbo.Items_RelativeItemID'可能會導致循環或多個級聯路徑。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY約束 無法創建約束或索引,請參閱前面的錯誤。「也許我只需要設置cascadeDelete爲false - 我不太瞭解這個屬性。 – Petr

+0

@Petr一種解決方案是禁用級聯刪除,另一種解決方案是使用流利的api來配置關係。我已經加入了答案。 – Klinger

1

想你也許可以用這脫身:

public class ItemRelation 
{ 

    public long Id { get; set; } 

    [ForeignKey("PrimaryItemId")] 
    public Item Item { get; set; } 
    public long PrimaryItemId { get; set; } 

    [ForeignKey("RelatedItemId")] 
    public Item RelatedItem { get; set; } 
    public long RelatedItemId { get; set; } 

    public ItemRelationType RelationType; 
} 

注意,這個類現在與Item實體有兩個關係,產生兩個外鍵。請注意,每個Item屬性都有一個[ForeignKey]屬性,字符串參數指定long用作外鍵列。

查看此答案,以輕推不同的音軌。更多地研究這個話題,看看它是否適合你的用例。