В MS SQL 2005 и выше вы можете создавать рекурсивные запросы.Однако в LINQ to SQL вам не повезло.Без реструктуризации данных в базе данных невозможно обойти дерево за один вызов базы данных.
Однако ... я могу придумать один обходной путь.Когда вы можете сгруппировать все Category
элементы одного дерева (или части дерева) вместе, вы можете предварительно загрузить эту часть полного дерева в одном операторе.После этого вы сможете пройти эту часть дерева, не вызывая новые вызовы в базу данных.Это будет выглядеть примерно так:
// Load the category that will be used as starting point.
var subCategory = db.Categories.Single(c => c.Id == 56);
// Performance: Load the complete group in one go.
var categories = (
from category in db.Categories
where category.GroupId == subCategory.GroupId
select category)
.ToArray();
// Traverse the tree and get the top-most parent (if any).
var parent = subCategory.GetParents().LastOrDefault();
// Extension method to get the parents.
public static IEnumerable<Category> GetParents(
this Category category)
{
while (category.Parent != null)
{
// NOTE: cat.Parent will not cause a database call
// when the Parent is already loaded by L2S.
yield return cat.Parent;
category = category.Parent;
}
}
Это, конечно, будет работать только в том случае, если вы сможете определять элементы как группу.Будет ли это решение быстрее, также зависит от размера группы.Когда группа объектов, которые вы загружаете (и не используете), очень велика, это фактически замедляет работу приложения.