多对多自引用关系

时间:2018-03-10 22:41:48

标签: c# entity-framework entity-framework-core

我是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 个答案:

答案 0 :(得分:10)

你关注的帖子肯定是错的。

每个集合或引用导航属性只能 成为单个关系的一部分。虽然与两个一对多关系实现了与显式连接实体的多对多关系。连接实体包含两个引用导航属性,但主实体只有单个集合导航属性,该属性必须与其中一个相关联,但不能与两者相关联。< / p>

解决此问题的一种方法是添加第二个集合导航属性:

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

并通过流畅的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与相应导航属性的存在/不存在完全匹配。

请注意,在这两种情况下,您必须关闭至少一个关系的删除级联,并在删除主实体之前手动删除相关的连接实体,因为自引用关系始终引入可能的周期或多个级联路径问题,阻止级联删除的使用。