Глубокая фильтрация в сгруппированном наборе сущностей - PullRequest
0 голосов
/ 20 июня 2019

У меня есть следующая схема сущностей:

class Container
{
 Forest Forest;
 Tree Tree;
}
class Forest 
{
  int Id;
  string Name;
  List<Trees> Trees;
}

class Tree 
{
 int Id;
 string Name;
 Forest Forest;
 List<Leaf> Leafs;
}

class Leaf 
{
 int Id;
 string Name;
 Tree Tree;
}

У меня есть коллекция Forest с включенным Trees and Leafs для чтения из базы данных.

Как я могу сделать следующее:

Отфильтруйте коллекцию Forests на основе следующего правила: Возьмите записи Фореста, у которых либо [Name] содержит некоторые "filter value" Или тех, у кого Trees [Name] содержит "filter value" Или тех, кто Leaf [Name] содержит "filter value".

Мне нужно вернуть иерархию леса, а не сплющенное представление леса

Я попытался сгладить структуру для фильтрации записей, например, таблицы в базе данных из INNER JOIN view

IEnumerable<Container> containers;
var groupped = forests.Select(f => new {f.Forest, f.Tree})
  .GroupBy(f => f.Forest)
  .ToList().Select(fs => new {Forest = fs.Key, Leafes = fs.SelectMany(g => g.Tree.Leafes) }).ToDictionary(fx => fx.Forest, fx => fx.Leafes);

var flat = new List<Tuple<Forest, Tree, Leaf>>;
foreach (var i in groupped)
{
 foreach (var l in i.Value) 
 {
  flat.Add((i.Key, l.Tree, l));
 }
}
flat.Where(d => d.Item1.Name.Contains("") 
  || d.Item2.Name.Contains("")
  || d.Item3.Name.Contains(""));       

Но на самом деле здесь я не могу объединить их обратно в иерархию Forest -> Tree -> Leaf

Итак, вместо какой-то табличной структуры List<Tuple<Forest,Tree,Leaf>> Iхотите иметь нормальную коллекцию List<Forest> с Trees и Leafs отфильтрованными.

1 Ответ

0 голосов
/ 20 июня 2019

Вы можете довольно легко создать набор фильтров Container из вашего списка Containers, просто внедрите желаемый фильтр в точности так, как вы его написали. (Это (не обязательно) самый эффективный способ поиска, но, вероятно, довольно близко.)

var ans = src.Where(c => c.Forest.Name.Contains(fv) || // Forest name contains filter value
                         c.Forest.Trees.Any(t => t.Name.Contains(fv) || // a Tree name contains filter value
                                                 t.Leafs.Any(l => l.Name.Contains(fv))) // a Leaf name contains filter value
                    );

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

var ans2 = src.Where(c => c.Forest.Name.Contains(fv) || // Forest name contains filter value
                          c.Forest.Trees.Any(t => t.Name.Contains(fv)) || // a Tree name contains filter value
                          c.Forest.Trees.Any(t => t.Leafs.Any(l => l.Name.Contains(fv))) // a Leaf name contains filter value
                    );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...