Вот способ LINQ сделать это.
Я принял определение Objective
примерно так:
public class Objective
{
public int ObjectiveId { get; set; }
public int? Parent_ObjectiveId { get; set; }
public string Name { get; set; }
public int Rank { get; set; }
}
Затем я создал класс поддержки с именем LevelObjective
чтобы захватить уровень (т. е. «1.3.1») примерно так:
public class LevelObjective
{
public Objective Objective { get; set; }
public string Level { get; set; }
}
И я начал с набора целей, определенных так:
var objectives = new []
{
new Objective { ObjectiveId = 1, Parent_ObjectiveId = null, Name = "Geometry", Rank = 1, },
new Objective { ObjectiveId = 2, Parent_ObjectiveId = 1, Name = "Squares", Rank = 1, },
new Objective { ObjectiveId = 3, Parent_ObjectiveId = 1, Name = "Circles", Rank = 2, },
new Objective { ObjectiveId = 4, Parent_ObjectiveId = 1, Name = "Triangle", Rank = 3, },
new Objective { ObjectiveId = 5, Parent_ObjectiveId = 4, Name = "Types", Rank = 1, },
new Objective { ObjectiveId = 6, Parent_ObjectiveId = null, Name = "Algebra", Rank = 2, },
new Objective { ObjectiveId = 7, Parent_ObjectiveId = null, Name = "Trigonometry", Rank = 3, },
};
Далее я создалпоиск, чтобы получить детей от любого идентификатора.
var lookup = objectives.ToLookup(x => x.Parent_ObjectiveId);
Я использовал этот поиск, чтобы создать набор целей верхнего уровня:
var roots = lookup[null]
.Select(o => new LevelObjective()
{
Objective = o,
Level = o.Rank.ToString(),
});
Затем я определил функциюэто выравнивает иерархию:
Func<
IEnumerable<LevelObjective>,
Func<LevelObjective, IEnumerable<LevelObjective>>,
IEnumerable<LevelObjective>> flatten = null;
flatten = (rs, f) =>
rs.Concat(
from r in rs
from c in flatten(f(r), f)
select c);
У меня уже был один из них, определенный как метод расширения, который использовал дженерики, но я просто преобразовал в лямбда-выражение, которое использовало LevelObjective
.
Iтеперь определил Func<LevelObjective, IEnumerable<LevelObjective>>
, необходимый для получения дочерних элементов любого LevelObjective
.
Func<LevelObjective, IEnumerable<LevelObjective>> getChildren = lo =>
from o in lookup[lo.Objective.ObjectiveId]
select new LevelObjective()
{
Objective = o,
Level = String.Format("{0}.{1}", lo.Level, o.Rank),
};
. Затем я мог бы создать полный список LevelObjective
объектов на основе исходного набора Objective
объектов.
var levelObjectives = flatten(roots, getChildren);
Наконец, я могу превратить это в карту от уровня к цели.
var map = levelObjectives.ToLookup(x => x.Level, x => x.Objective);
Теперь, чтобы найти любой объектМне просто нужно вызвать этот код:
var objective = map["1.3.1"].FirstOrDefault();
Так что теперь у меня есть функция, которая будет возвращать ноль или более целей для любого предоставленного ключа уровня.Приятно то, что это выполнит только один запрос к базе данных, и вызовы функции map
будут возвращены в o (1) раз.
Это работает для вас?