Используйте Linq для запроса терминальных / конечных узлов в иерархической таблице / Составном шаблоне
-
03-07-2019 - |
Вопрос
У меня есть таблица с самоссылками с идентификатором, CategoryName и ParentID .Это типичный сценарий иерархической таблицы категорий, которые сами по себе могут быть разделены на категории, которые, по словам экспертов DB, называются моделью смежности.
Что я хочу, так это использовать Linq to SQL для запроса подкатегорий, которые сами по себе не связаны ни с какими другими подкатегориями, т. Е. Они являются непосредственными конечными узлами некоторой заданной категории или подкатегории.
У меня есть самая простая часть, которая заключается в том, чтобы просто получить подкатегории.Почти стесняюсь помещать сюда код.Но нам действительно нравится видеть код..
IList<Categories> subcategories = context.Where( c => c.ParentId == 1).ToList();
Но сужение списка до категорий без подкатегорий меняет меня.Любая помощь была бы высоко оценена.
Спасибо вам за помощь.Джефф
Обновить** Казалось бы, это работает, но если бы кто-нибудь мог подтвердить, что это "правильно", я был бы благодарен.Итак, если я хочу, чтобы конечные узлы относились к категории с Id = 1, я бы сделал это:
Categories.Where( c => !c.Children.Any ( d => d.ParentId == c.Id)).Where( e => e.ParentId == 1)
"Дети" - это название, которое Linq дает самоссылающейся ассоциации.
Решение
Ваше решение правильное, потому что Any()
метод, преобразующий в sql функцию "EXISTS()"
и !c.Children.Any ( d => d.ParentId == c.Id))
преобразуется в предложение sql , аналогичное NOT EXISTS (SELECT * FROM Categories WHERE ParentID = outerRef.ID)
Другой способ сделать это - использовать Count
:
Categories.Where( c => c.Children.Count(d => d.ParentId == c.Id) == 0).Where( e => e.ParentId == 1)
Но обычно EXISTS() предпочтительнее COUNT() в sql (по соображениям производительности), поэтому решение с помощью Any() должно быть правильным.
Другие советы
Я думаю, если я правильно понимаю ваш вопрос, вы пытаетесь получить все дочерние элементы, у которых нет собственных дочерних элементов...этот запрос самостоятельно соединяет таблицу с самим собой, чтобы проверить, используется ли узел в качестве родительского, если это не так, то он отображается в результате.
Я не уверен, работает ли это, поскольку мне не на чем это проверить...
(from c in context
join cc in context on c.id equals cc.parentid into temp
from t in temp.DefaultIfEmpty()
where t == null
select c).ToList()