2011-10-11 155 views
1

我有一个简单的对象列表“ProductGroups”(IQueryable)。 每个“ProductGroup”都有一个称为“Children”的ProductGroups集合,一个整数ParentId字段和一个布尔型“IsEnabled”字段。用LINQ过滤整个分层列表

public class ProductGroup 
{ 
    public int Id; 
    public int ParentId; 
    public ICollection<ProductGroup> Children; 
    public bool IsEnabled; 
} 

我希望能够返回“IsEnabled”为true的ProductGroups树。

此刻,如果我做

ProductGroups.Where(x => x.IsEnabled) 

这将返回功能的产品。如果我做

ProductGroups.Where(x => x.ParentId == null) 

这将返回根。我希望能够以尽可能最小的方式返回完整的树(不包括禁用的项目)(即在查询集合后不使用for循环)。

ProductGroup1 (IsEnabled == true) 
    | 
    --------- ProductGroup2 (IsEnabled == true) 
    |    | 
    |    ----------- ProductGroup4 (IsEnabled == false) 
    | 
    --------- ProductGroup4 (IsEnabled == false) 

即返回ProductGroup1与1名儿童ProductGroup2

感谢

+0

LINQ总是会返回一个平坦的IEnumerable,所以你要查找的内容(真的)是树的根?真的吗?如果是这样,为什么不向ProductGroup添加一个返回已启用子项(仅)的函数并将该函数与您的根一起使用?或者你真的试图让IEnumerable包含所有已启用的节点及其子节点到树叶? – Kevek

回答

0

我不知道你与过滤收集的具体需求。我正在将它看作View-Model。和递归扩展方法为您提供了一个巧妙的方法来实现这个过滤器:

public static class Helper 
{ 
    public static ICollection<ProductGroup> EnabledWithChildren(this ICollection<ProductGroup> source) 
    { 
     var result = new List<ProductGroup>(); 
     foreach (var ele in source) 
     { 
      if(ele.IsEnabled == true) 
      { 
       var productGroup = new ProductGroup{Id = ele.Id, IsEnabled = ele.IsEnabled, ParentId = ele.ParentId}; 
       if(ele.Children != null && ele.Children.Count() > 0) 
        productGroup.Children = ele.Children.EnabledWithChildren(); 
       result.Add(productGroup); 
      } 
     } 
     return result; 
    }  
} 

与用法:

public class ProductGroup 
{ 
    public int Id; 
    public int? ParentId; 
    public ICollection<ProductGroup> Children; 
    public bool IsEnabled; 

    static void Main() 
    { 
     var filteredProductGroups = ProductsGroups.EnabledWithChildren(); 
    } 
} 
+0

问题在于,所有产品组都将在过滤之前加载到内存中。如果可能的话,我想让EF使用一些巧妙的LINQ来进行过滤,即对IQueryable进行过滤,以便只从数据库返回所需的记录。我的数据集可能有数百万条记录,所以重要的是我可以使用EF来正确地过滤记录。 – SturmUndDrang