2016-12-26 125 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用作外键列。

查看此答案,以轻推不同的音轨。更多地研究这个话题,看看它是否适合你的用例。