2015-11-14 3 views
1

У меня есть класс, как это:Создание нескольких автореферентных внешних ключей к одной и тем же таблицам

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

} 

Когда я создаю базу данных из этого определения класса, я получаю ошибку:

Unable to determine the principal end of an association between the types 'Tree' and 'Tree'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.

Если я удалю одно из свойств и создаю определение класса следующим образом:

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

} 

Он создает правильное значение t Ables. Как я могу получить эту ошибку? Я попытался указать порядок столбцов, добавив уникальный индекс. Я могу обойти это, используя List TreeOne, и он создаст соответствующую таблицу ссылок, но я бы предпочел не использовать это решение.

ответ

2

Основная проблема заключается в том, что SQL не позволит вам точно определить двоичное дерево.

В вашем подходе можно, чтобы элемент дерева имел несколько родителей, поскольку ничто не мешает LeftId и RightId указывать на одну и ту же ссылку или иметь другой элемент дерева, указывающий на одно и то же поддерево.

Нам нужна определенная конечная точка для свойств навигации слева или справа. Это ключ к решению: определите отдельное свойство обратной навигации для дочерних элементов слева и справа и учтите, что у вас есть несколько родителей.

Имея это в виду, позволяет настроить модель для сущности. Обратите внимание, что я заменил Tree на TreeItem, так как его одна запись на каждый узел дерева и использовалась 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

+0

Удивительный раствор. Я видел много примеров, которые показали, как использовать это отношение между двумя классами, но не содержаться в одном классе. – Magn3s1um