同时使用多对多和一对多同一实体

Mar*_*ijn 6 c# many-to-many entity-framework one-to-many

我在EF Code-First中有一个多对多的关联(正如本问题中所解释的那样),我也希望对同一个实体使用一对多关系.问题是EF无法生成正确的数据库方案.码:

public class A
{
  public int Id { get; set; }
  public string Name { get; set; }
  public virtual ICollection<B> ObjectsOfB { get; set; }
}

public class B
{
  public int Id { get; set; }
  public virtual A ObjectA { get; set; }
  public virtual ICollection<A> OtherObjectsOfA { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

当我删除B类的ObjectA属性时,会正确生成多对多关联.当生成不正确时,实体B获得2个外键到A,实体A获得1个外键到B(如多对一关系).

Sla*_*uma 16

如果您有多个导航属性引用同一实体,则EF不知道另一个实体上的反向导航属性所属的位置.在您的示例中:是否A.ObjectsOfB引用B.ObjectA或B.OtherObjectsOfA?两者都是可能的并且是有效的模型.

现在,EF不会抛出像"无法明确地确定关系"之类的异常.相反,它决定B.ObjectA引用第三个端点,B其中未在模型中公开为导航属性.这将在表中创建第一个外键B.这两个导航性质B是指两个端点在A其中也没有在模型中暴露:B.ObjectA外币在表中的第二外键B和B.OtherObjectsOfA创建表的外键A.

要解决此问题,您必须明确指定关系.

选项一(最简单的方法)是使用InverseProperty属性:

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
    [InverseProperty("OtherObjectsOfA")]
    public virtual ICollection<B> ObjectsOfB { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这定义了它A.ObjectsOfB是多对多关系的一部分B.OtherObjectsOfA.

另一种选择是在Fluent API中完全定义关系:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<A>()
        .HasMany(a => a.ObjectsOfB)
        .WithMany(b => b.OtherObjectsOfA)
        .Map(x =>
        {
            x.MapLeftKey("AId");
            x.MapRightKey("BId");
            x.ToTable("ABs");
        });

    modelBuilder.Entity<B>()
        .HasRequired(b => b.ObjectA)  // or HasOptional
        .WithMany()
        .WillCascadeOnDelete(false);  // not sure if necessary, you can try it
                                      // without if you want cascading delete
}
Run Code Online (Sandbox Code Playgroud)