同时使用多对多和一对多同一实体
我在EF Code-First中有一个多对多的关联(正如本问题中所解释的那样),我想对同一个实体使用一对多关系。 问题是EF没有产生正确的数据库方案。 码:
public class A { public int Id { get; set; } public string Name { get; set; } public virtual ICollection ObjectsOfB { get; set; } } public class B { public int Id { get; set; } public virtual A ObjectA { get; set; } public virtual ICollection OtherObjectsOfA { get; set; } }
当我删除B类的ObjectA属性时,会正确生成多对多关联。 当生成不正确时,实体B获得2个外键到A,实体A获得1个外键到B(就像多对一关系一样)。
如果您有多个导航属性,则引用同一实体EF不知道另一个实体的逆导航属性属于何处。 在您的示例中: A.ObjectsOfB
是指B.ObjectA
还是B.OtherObjectsOfA
? 两者都是可能的并且是有效的模型。
现在,EF不会抛出像“无法明确地确定关系”之类的exception。 相反,它决定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 ObjectsOfB { get; set; } }
这定义A.ObjectsOfB
是A.ObjectsOfB
的多对多关系的B.OtherObjectsOfA
。
另一种选择是在Fluent API中完全定义关系:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity() .HasMany(a => a.ObjectsOfB) .WithMany(b => b.OtherObjectsOfA) .Map(x => { x.MapLeftKey("AId"); x.MapRightKey("BId"); x.ToTable("ABs"); }); modelBuilder.Entity() .HasRequired(b => b.ObjectA) // or HasOptional .WithMany() .WillCascadeOnDelete(false); // not sure if necessary, you can try it // without if you want cascading delete }