实体框架建模一个一对多的关系
我不知道如何在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 - 但我不知道我怎么...
你缺少实际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
删除惯例,如果您还没有,在你的上下文类如下:
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.
是的。但通过这种方式,我有以下错误:“在表'ItemRelations'上引入FOREIGN KEY约束'FK_dbo.ItemRelations_dbo.Items_RelativeItemID'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束 无法创建约束或索引,请参阅前面的错误。“也许我只需要设置cascadeDelete为false - 我不太了解这个属性。 – Petr
@Petr一种解决方案是禁用级联删除,另一种解决方案是使用流利的api来配置关系。我已经加入了答案。 – Klinger
想你也许可以用这脱身:
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
用作外键列。
查看此答案,以轻推不同的音轨。更多地研究这个话题,看看它是否适合你的用例。
“一些语言词典模型”,“一些关系“,”一些错误“,”一个案例 - 另一个案例“ - 这些都很模糊。 –