Entity Framework 建模一对多关系
Entity Framework modelling one-to-many relationship
我不知道如何在 EF 中配置以下关系:
假设我需要创建一些语言词典模型。我有一个项目(例如单词)用一种语言和另一种语言。这两项之间存在某种关系。
例如:"hund"(德语)-> "dog"(英语),关系类型为"Translate"
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 标准迁移在一种情况下抛出一些错误,或者在另一种情况下创建我不会使用的列或 FK(Item_ID
等)。
我想我需要配置一些流畅的 api - 但我不确定如何...
我想你或许可以摆脱这个:
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;
}
请注意,此 class 现在与 Item
实体有两个关系,从而产生两个外键。请注意,每个 Item
属性 都有一个 [ForeignKey]
属性,字符串参数指定 long
用作外键列。
将此答案视为对不同轨道的推动。进一步研究这个主题,看看它是否适合您的用例。
您缺少实际的 FK 字段 ItemID
和 RelativeItemID
:
要配置导航 属性,您可以使用 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
禁用级联删除约定,如果您还没有这样做,在您的上下文 class 中如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
...
此解决方案应该有效,但它实际上禁用了对所有一对多关系的级联删除。好处是你可以通过使用流利的 api.
根据具体情况取回它
实现你想要的第二种方法是使用 fluent api 如下:
将第二个导航 属性 添加到您的 Item
实体:
public class Item
{
...
public virtual ICollection<ItemRelation> RelativeItemRelations { get; set; }
...
}
ItemRelation
实体缺少 FK,所以这里是:
public class ItemRelation
{
public 长 ID { 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; }
}
并且要配置导航 属性,并避免级联问题,您只需使用 fluent 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.
我不知道如何在 EF 中配置以下关系:
假设我需要创建一些语言词典模型。我有一个项目(例如单词)用一种语言和另一种语言。这两项之间存在某种关系。
例如:"hund"(德语)-> "dog"(英语),关系类型为"Translate"
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 标准迁移在一种情况下抛出一些错误,或者在另一种情况下创建我不会使用的列或 FK(Item_ID
等)。
我想我需要配置一些流畅的 api - 但我不确定如何...
我想你或许可以摆脱这个:
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;
}
请注意,此 class 现在与 Item
实体有两个关系,从而产生两个外键。请注意,每个 Item
属性 都有一个 [ForeignKey]
属性,字符串参数指定 long
用作外键列。
将此答案视为对不同轨道的推动。进一步研究这个主题,看看它是否适合您的用例。
您缺少实际的 FK 字段 ItemID
和 RelativeItemID
:
要配置导航 属性,您可以使用 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
禁用级联删除约定,如果您还没有这样做,在您的上下文 class 中如下所示:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
...
此解决方案应该有效,但它实际上禁用了对所有一对多关系的级联删除。好处是你可以通过使用流利的 api.
根据具体情况取回它实现你想要的第二种方法是使用 fluent api 如下:
将第二个导航 属性 添加到您的 Item
实体:
public class Item
{
...
public virtual ICollection<ItemRelation> RelativeItemRelations { get; set; }
...
}
ItemRelation
实体缺少 FK,所以这里是:
public class ItemRelation { public 长 ID { 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; }
}
并且要配置导航 属性,并避免级联问题,您只需使用 fluent 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.