对同一实体同时使用多对多和一对多
本文关键字:一对多 实体 | 更新日期: 2023-09-27 18:15:29
我在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; }
}
当我删除类B的ObjectA属性时,正确地生成了多对多关联。当生成错误时,实体B获得2个指向A的外键,实体A获得1个指向B的外键(类似于多对一关系)。
如果您有多个导航属性引用同一实体,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; }
}
这定义了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
}
如果表B有指向表A的外键,则类B有指向表A的导航属性,类A也有指向ICollection<A>
的导航属性。
如果表B和表A有多对多关系,则类A必须有ICollection<B>
,类B必须有ICollection<A>
。
试试,也许这会让EF明白你的要求。