实体框架建模一对多关系

时间:2016-12-26 19:36:47

标签: entity-framework one-to-many

我不知道如何在EF中配置以下关系:

想象一下,我需要创建一些语言字典模型。我有一种语言(例如单词)用一种语言和另一种语言。这两个项目之间存在某种关系。

例如:" hund" (德语) - > "狗" (英文),关系类型是"翻译"

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标准迁移会在一种情况下抛出一些错误,或者在另一种情况下创建我不会(Item_ID等)的列或FK。

我想我需要配置一些流畅的api - 但我不确定如何......

2 个答案:

答案 0 :(得分: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

将此答案视为对不同曲目的推动。更多地研究这个主题,看它是否适合您的用例。

答案 1 :(得分: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实体缺少FK,所以这里是:

公共类ItemRelation     {        公共长身份证{get;组; }

   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; }
}

要配置导航属性并避免级联问题,您只需使用流畅的api定义关系:

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.