C# 在M和N都是相同实体的情况下,如何建立M:N(多对多)关系?

C# 在M和N都是相同实体的情况下,如何建立M:N(多对多)关系?,c#,entity-framework,C#,Entity Framework,我在实体框架方面有困难。我正试图建立一个数据模型,实体通过一个连接表引用它的对立面 我已经创建了实体样式和连接表样式 [Table("Styles")] public class Style : FullAuditedEntity { public virtual string Name { get; set; } public virtual string ShortName { get; set; } public List<StyleXStyle>

我在实体框架方面有困难。我正试图建立一个数据模型,实体通过一个连接表引用它的对立面

我已经创建了实体样式和连接表样式

[Table("Styles")]
public class Style : FullAuditedEntity
{
    public virtual string Name { get; set; }

    public virtual string ShortName { get; set; }

    public List<StyleXStyle> Opposites { get; set; } = new List<StyleXStyle>();
}
尝试添加数据库迁移时,出现以下错误:


无法确定由类型为“List”的导航属性“Style.opposities”表示的关系。手动配置关系,或者使用“[NotMapped]”属性或使用“OnModelCreating”中的“EntityTypeBuilder.ignore”忽略此属性。

由于您需要自引用
样式
实体的集合,因此对于此多对多映射,您应该有两个集合属性。一个导航到你的对立面,另一个导航到“alikes”。在我的示例中,我包含了第二个名为
Alikes
的列表属性

这样,您就可以包括一个自定义映射,告诉EF这些映射是如何相关的:

使用基于属性的配置:

public class Style : FullAuditedEntity
{   
    [InverseProperty("Style")] 
    public List<StyleXStyle> Alikes { get; set; } = new List<StyleXStyle>();
    [InverseProperty("Opposite")]
    public List<StyleXStyle> Opposites { get; set; } = new List<StyleXStyle>();
}

public class StyleXStyle : FullAuditedEntity
{
    [ForeignKey("Opposite")]
    public virtual int OppositeId { get; set; }
    public Style Opposite { get; set; }

    [ForeignKey("Style")]
    public virtual int StyleId { get; set; }
    public Style Style { get; set; }
}
公共类样式:FullAuditedEntity
{   
[反向属性(“样式”)]
公共列表Alikes{get;set;}=new List();
[反向属性(“反向”)]
公共列表对立面{get;set;}=new List();
}
公共类StyleXStyle:FullAuditedEntity
{
[外键(“对方”)]
公共虚拟int-OppositeId{get;set;}
公共样式对立面{get;set;}
[外键(“样式”)]
公共虚拟int-StyleId{get;set;}
公共样式样式{get;set;}
}
使用Fluent API:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // configures one-to-many relationship
    modelBuilder.Entity<StyleXStyle>()
        .HasRequired<Style>(s => s.Style)
        .WithMany(g => g.Alikes)
        .HasForeignKey<int>(s => s.StyleId);          

    // configures one-to-many relationship
    modelBuilder.Entity<StyleXStyle>()
        .HasRequired<Style>(s => s.Opposite)
        .WithMany(g => g.Opposites)
        .HasForeignKey<int>(s => s.OppositeId);          
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
//配置一对多关系
modelBuilder.Entity()
.HasRequired(s=>s.Style)
.有许多(g=>g.相似物)
.HasForeignKey(s=>s.StyleId);
//配置一对多关系
modelBuilder.Entity()
.HasRequired(s=>s.reversit)
.有许多(g=>g.对立面)
.HasForeignKey(s=>s.OppositeId);
}
上面对连接实体/表执行映射,以便您可以将其用作多对多关系。如果您需要跟踪关系本身的任何信息(例如,CreatedDate、CreatedBy、RelationDate等),这是必要的。但是,如果您不需要关系实体的其他信息,EF提供了自己的方法来按照约定映射此信息

在后一种情况下,您可以将实体直接映射到彼此,并完全忽略关系表。下面是一个简单的例子:

[Table("Styles")]
public class Style : FullAuditedEntity
{
    public virtual string Name { get; set; }

    public virtual string ShortName { get; set; }

    public ICollection<Style> Opposites { get; set; }
    public ICollection<Style> Alikes { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

    modelBuilder.Entity<Style>()
                .HasMany<Style>(s => s.Alikes)
                .WithMany(c => c.Opposites)
                .Map(cs =>
                        {
                            cs.MapLeftKey("OppositeId");
                            cs.MapRightKey("StyleId");
                            cs.ToTable("StyleXStyle");
                        });

}
[表格(“样式”)]
公共类样式:FullAuditedEntity
{
公共虚拟字符串名称{get;set;}
公共虚拟字符串短名称{get;set;}
公共ICollection对立面{get;set;}
公共ICollection Alikes{get;set;}
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasMany(s=>s.Alikes)
.有许多(c=>c.对立面)
.Map(cs=>
{
cs.MapLeftKey(“反对党”);
cs.MapRightKey(“StyleId”);
cs.ToTable(“StyleXStyle”);
});
}
上面的代码是为您的示例而编写的,我没有完全测试它,但以前也以相同的方式实现了它

[Table("Styles")]
public class Style : FullAuditedEntity
{
    public virtual string Name { get; set; }

    public virtual string ShortName { get; set; }

    public ICollection<Style> Opposites { get; set; }
    public ICollection<Style> Alikes { get; set; }
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{

    modelBuilder.Entity<Style>()
                .HasMany<Style>(s => s.Alikes)
                .WithMany(c => c.Opposites)
                .Map(cs =>
                        {
                            cs.MapLeftKey("OppositeId");
                            cs.MapRightKey("StyleId");
                            cs.ToTable("StyleXStyle");
                        });

}