创建多个自引用外键到同一个表

时间:2015-11-14 17:18:59

标签: c# entity-framework-6

我有一个这样的课程:

[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; }

}

当我从这个类定义创建数据库时,我收到错误:

  

无法确定类型“树”和“树”之间关联的主要结束。必须使用关系流畅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; }

}

它确实创建了正确的表格。我怎么能得到这个错误?我已经尝试指定列顺序,添加一个唯一索引。我可以通过使用List TreeOne解决这个问题,它将创建相应的链接表,但我宁愿不必使用该解决方案。

1 个答案:

答案 0 :(得分:2)

这里的基本问题是,SQL不允许您精确定义二叉树。

在你的方法中,树项有可能有多个父项,因为没有什么能阻止LeftId和RightId指向同一个引用或者让另一个树项指向同一个子树。

我们需要为左/右导航属性定义一个终点。这是解决方案的关键:为左/右子项定义单独的反向导航属性,并考虑是否有多个父项。

考虑到这一点,让我们为实体框架设置模型。请注意,我将Tree替换为TreeItem,因为每个树节点有一个条目,并使用LeftRight代替您的属性名称,而不是懒惰。

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