正在为同一个表创建多个自引用外键
本文关键字:自引用 创建 同一个 | 更新日期: 2023-09-27 18:22:04
我有一个这样的类:
[Table("Tree")]
public class Tree
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TreeId { get; set; }
public int? TreeOneId { get; set; }
[ForeignKey("TreeOneId")]
public virtual Tree TreeOne { get; set; }
public int? TreeTwoId { get; set; }
[ForeignKey("TreeTwoId")]
public virtual Tree TreeTwo { get; set; }
}
当我从这个类定义创建数据库时,我得到了错误:
无法确定类型"树"answers"树"之间关联的主体端。此关联的主体端必须使用关系fluent API或数据注释显式配置。
如果我删除其中一个属性,并创建一个类定义,如下所示:
[Table("Tree")]
public class Tree
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int TreeId { get; set; }
public int? TreeOneId { get; set; }
[ForeignKey("TreeOneId")]
public virtual Tree TreeOne { get; set; }
//public int? TreeTwoId { get; set; }
//[ForeignKey("TreeTwoId")]
//public virtual Tree TreeTwo { get; set; }
}
它确实创建了正确的表。我怎样才能克服这个错误?我已经尝试指定列顺序,添加一个唯一的索引。我可以通过使用ListTreeOne来解决这个问题,它将创建相应的链接表,但我宁愿不必使用该解决方案。
这里的基本问题是,SQL不允许精确定义二进制树。
在您的方法中,一个树项可能有多个父项,因为没有什么可以阻止LeftId和RightId指向同一引用或使另一个树项目指向同一子树。
我们需要为Left/Right上的导航属性定义一个端点。这是解决方案的关键:为左/右子项定义一个单独的反向导航属性,并考虑到有多个父项的可能性。
考虑到这一点,让我们为实体框架建立模型。注意,我用TreeItem
替换了Tree
,因为它每个树节点只有一个条目,并使用了Left
、Right
而不是您的属性名称。
public class TreeItem
{
public int Id { get; set; }
public int? LeftId { get; set; }
public int? RightId { get; set; }
[ForeignKey("LeftId")]
[InverseProperty("Parent1")]
public virtual TreeItem Left { get; set; }
[ForeignKey("RightId")]
[InverseProperty("Parent2")]
public virtual TreeItem Right { get; set; }
[InverseProperty("Left")]
public virtual ICollection<TreeItem> Parent1 { get; set; }
[InverseProperty("Right")]
public virtual ICollection<TreeItem> Parent2 { get; set; }
}
另请注意:我只在EF6中进行了测试,因此不能保证使用EF5