多对多自引用关系
Posted
技术标签:
【中文标题】多对多自引用关系【英文标题】:Many-to-many self referencing relationship 【发布时间】:2018-08-19 06:20:23 【问题描述】:我是 EF 的新手。我遇到了创建的问题。 我尝试使用以下解决方案:Entity Framework Core: many-to-many relationship with same entity
我的实体:
public class WordEntity
public long Id get; set;
public string Name get; set;
public string Json get; set;
public virtual List<WordSinonymEntity> Sinonyms get; set;
public class WordSinonymEntity
public long WordId get; set;
public virtual WordEntity Word get; set;
public long SinonymId get; set;
public virtual WordEntity Sinonym get; set;
和下一个配置:
modelBuilder.Entity<WordSinonymEntity>()
.HasOne(pt => pt.Sinonym)
.WithMany(p => p.Sinonyms)
.HasForeignKey(pt => pt.SinonymId);
modelBuilder.Entity<WordSinonymEntity>()
.HasOne(pt => pt.Word)
.WithMany(t => t.Sinonyms)
.HasForeignKey(pt => pt.WordId);`
但它会导致下一个异常。
System.InvalidOperationException: '无法在 'WordEntity.Sinonyms' 和 'WordSinonymEntity.Word' 之间创建关系,因为 'WordEntity.Sinonyms' 和 'WordSinonymEntity.Sinonym' 之间已经存在关系。导航属性只能参与单个关系。'
有没有人可以帮助我或者可以建议一些例子来学习? 谢谢。
【问题讨论】:
【参考方案1】:您关注的帖子肯定是错误的。
每个集合或引用导航属性只能成为单个关系的一部分。虽然与显式连接实体的多对多关系是通过 two 一对多关系实现的。连接实体包含两个引用导航属性,但主实体只有单个集合导航属性,它必须与其中一个关联,但不能同时与两者关联。
解决此问题的一种方法是添加第二个集合导航属性:
public class WordEntity
public long Id get; set;
public string Name get; set;
public string Json get; set;
public virtual List<WordSinonymEntity> Sinonyms get; set;
public virtual List<WordSinonymEntity> SinonymOf get; set; // <--
并通过 fluent API 指定关联:
modelBuilder.Entity<WordSinonymEntity>()
.HasOne(pt => pt.Sinonym)
.WithMany(p => p.SinonymOf) // <--
.HasForeignKey(pt => pt.SinonymId)
.OnDelete(DeleteBehavior.Restrict); // see the note at the end
modelBuilder.Entity<WordSinonymEntity>()
.HasOne(pt => pt.Word)
.WithMany(t => t.Sinonyms)
.HasForeignKey(pt => pt.WordId);
另一种方法是保持模型不变,但将WordSinonymEntity.Sinonym
映射到单向 关联(具有引用导航属性且没有相应的集合导航属性):
modelBuilder.Entity<WordSinonymEntity>()
.HasOne(pt => pt.Sinonym)
.WithMany() // <--
.HasForeignKey(pt => pt.SinonymId)
.OnDelete(DeleteBehavior.Restrict); // see the note at the end
modelBuilder.Entity<WordSinonymEntity>()
.HasOne(pt => pt.Word)
.WithMany(t => t.Sinonyms)
.HasForeignKey(pt => pt.WordId);
只需确保WithMany
与相应导航属性的存在/不存在完全匹配即可。
请注意,在这两种情况下,您都必须为至少一个关系关闭删除级联,并在删除主实体之前手动删除相关的连接实体,因为自引用关系总是会引入可能的循环或多个级联路径 问题,阻止使用级联删除。
【讨论】:
非常感谢。我已经尝试了两种解决方案的变体,并且两种变体都很完美。我浪费了很多时间来寻找答案。我不得不在 *** 上早点提出这个问题。 嘿,Ivan 先生,如果我真的需要级联怎么办,我有类似的方法,我需要onUpdate: ReferantialAction.Cascade
,您能告诉我吗? :)
@Burak 呵呵,当然。但是......不幸的是,EF Core 不支持更新(修改)密钥,因此没有流畅的配置。您必须手动修改生成的迁移,然后通过原始 SQL 命令执行更新,因为如开头所述,EF Core 不会让您通过上下文 API 更改实体 PK。
你能检查一下这个问题吗...***.com/questions/63472076/…
很晚才提出其他问题,但我正在解决类似的问题。在此示例中,如何从 WordEntity 返回它所属的所有同义词的列表? IE。 Synonyms 和 SynonymsOf 的串联列表。我的第一个想法是简单地添加另一个带有 getter 的属性,该 getter 完全返回 (Synonyms.Concat(SynonymsOf)),但是有 EF Core 方法吗?以上是关于多对多自引用关系的主要内容,如果未能解决你的问题,请参考以下文章