Ходить по иерархической таблице с Linq - PullRequest
3 голосов
/ 01 апреля 2010

У меня есть таблица с двумя столбцами, GroupId и ParentId (оба являются GUIDS). Таблица образует иерархию, поэтому я могу искать значение в поле «GroupId», когда я его нашел, я могу посмотреть на его ParentId. Этот ParentId также появится в GroupId другой записи. Я могу использовать это для перехода по иерархическому дереву от любой точки к корню (корень - пустой GUID). То, что я хотел бы сделать, это получить список записей, когда я знаю GroupId. Это будет запись с GroupId, и все родители вернутся к корневой записи. Возможно ли это с помощью Linq, и если да, может ли кто-нибудь предоставить фрагмент кода?

Ответы [ 3 ]

5 голосов
/ 01 апреля 2010

LINQ не предназначен для обработки рекурсивного выбора.

Конечно, можно написать собственный метод расширения, чтобы компенсировать это в LINQ to Objects, но я обнаружил, что LINQ to Entities не нравится функциональность, которую нелегко перевести на SQL.

Edit: Как ни странно, LINQ to Entities не жалуется на рекурсию Мэтта Уоррена, использующую LINQ здесь . Вы могли бы сделать:

var result = db.Table.Where(item => item.GroupId == 5)
                     .Traverse(item => db.Table.Where(parent 
                                                       => item.ParentId == parent.GroupId));

с использованием метода расширения, определенного здесь:

static class LinqExtensions
{
    public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source,
                                             Func<T,IEnumerable<T>> selector){
    foreach(T item in source){
        yield return item;
        IEnumerable<T> children = selector(item);
        foreach (T child in children.Traverse(selector))
        {
            yield return child;
        }
    }
}

Впрочем, производительность может быть плохой.

1 голос
/ 01 апреля 2010

Это определенно возможно с Linq, но вам придется выполнять вызов БД для каждого уровня в иерархии. Не совсем оптимально.

0 голосов
/ 01 апреля 2010

Другие респонденты правы - производительность будет довольно плохой, так как вам придется совершать многократные обходы. Однако это будет несколько зависеть от вашего конкретного случая - ваше дерево глубоко, и люди будут часто выполнять эту операцию, например.

Вы можете получить хорошее обслуживание, создав хранимую процедуру, которая делает это (используя CTE), и связав ее в конструкторе сущностей, чтобы вернуть определенную вами сущность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...