实体分组集合中的深层过滤

时间:2019-06-20 09:05:48

标签: c# .net entity-framework linq

我有以下实体方案:

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视图中的数据库表

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>>的表格结构,而是希望有一个普通集合List<Forest>,其中过滤了TreesLeafs

1 个答案:

答案 0 :(得分:0)

您可以很容易地从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
                    );

如果层次结构中的树木很少,叶子很多,那么您可能希望将搜索更改为首先搜索树木,然后进行单独的tree-> leaf搜索,即使这两次穿过树木也是如此。

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
                    );