2012-02-11 139 views
3

我正在尝试执行以下操作。动态过滤linq lambda表达式

var groups = MileId == null ? test.Groups.Where(x => x.ProjectId == ProjectId) 
          : test.Groups.Where(x => x.Milestone == MileId && 
                x.ProjectId == ProjectId); 

但我也有我需要通过筛选组附加条款:

foreach (var ChartItem in ChartItems) 
{ 
    foreach (var StatusItem in ChartItem.ChartStatusItems) 
    { 
      foreach (var PriorityItem in StatusItem.ChartPriorityItems) 
      { 
       filteredgroups.AddRange(
        groups.Where(x => x.Status == StatusItem.StatusID 
           && x.Priority == PriorityItem.PriorityID)); 
      } 
    } 
} 

这无关紧要,它的工作原理,但添加范围时嵌套的foreach循环是相当缓慢的。如果我在循环之前对groups.toList()进行处理,那么该语句很慢并且嵌套循环很快。

我的问题是:

是否可以从基于这些StatusIds和PriorityIds动态开始筛选群体?怎么样?

Stackoverflow推荐一些基于我的主题行的表达式树的文章...是我需要看什么?

谢谢

编辑:

所以我现在这样做:

 foreach (var ChartItem in ChartItems) 
     { 
      foreach (var StatusItem in ChartItem.ChartStatusItems) 
      { 
       foreach (var PriorityItem in StatusItem.ChartPriorityItems) 
       { 

        var groups = MileId == null ? test.Groups.Where(x => x.ProjectId == InspectorProjectId && 
                        x.Status == StatusItem.StatusID && 
                        x.Priority == PriorityItem.PriorityID) 
                 : test.Groups.Where(x => x.Milestone == InspectorMileId && 
                        x.ProjectId == InspectorProjectId && 
                        x.Status == StatusItem.StatusID && 
                        x.Priority == PriorityItem.PriorityID); 

        filteredgroups.AddRange(groups); 
       } 
      } 
     } 

这是一个很大的进步,但它仍然要为每个优先级慢“测试”服务器。如果我能把它全部过滤掉,这将是理想的。

编辑2:哦,我没有访问数据库直接:(我们通过API访问

+1

什么是'test.Groups'?那是访问一个数据库吗?列表中包含的项目大约有多少? – svick 2012-02-11 20:31:53

+0

是的,这是正确的,test.groups正在访问一个数据库。过滤之前,组包含约10k项目。 – Robodude 2012-02-11 20:33:08

回答

1

你能与Contains

var filteredgroups = 
    test.Groups.Where(x => 
    (MileId == null || x.Milestone == MileId) // (replaces ?: in original) 
    && x.ProjectId == ProjectId 
    && ChartItem.ChartStatusItems.Contains(x.Status) 
    && StatusItem.ChartPriorityItems.Contains(x.Priority)); 

做到这一点(我不是确定Linq-to-Sql和Linq-to-Objects如何与性能交互,但至少它是简洁的......)

+0

我真的结束了在这里做类似的事情,但不是使用包含我只是 x.Status == StatusItem.StatusID && x.Priority == PriorityItem.PriorityID – Robodude 2012-02-11 20:40:36

0

foreach循环最有可能执行延期调用,这很可能会触及你的数据库上每个foreach循环。但你不必使用SelectMany你可以简单地建立查询:

var statuses = ChartItems 
        .SelectMany(x => x.ChartStatusItems) 
        .Select(i => i.StatusId); 
var priorities = ChartItems 
        .SelectMany(x => x.ChartPriorityItems) 
        .Select(i => i.PriorityId); 

var filtered = groups.Where(x => statuses.Contains(x.Status) && 
           priorities.Contains(x.Priority)) 
4

这一切都应该在数据库发生。只需创建一个加入所有这些表的视图。在交叉和连接数据集时,很难比数据库更快。

+0

是的,我最终以类似的方式优化它(见编辑)。你推荐什么? – Robodude 2012-02-11 20:50:35

+0

恐怕创建视图不是一个选项,因为我没有直接访问数据库。相反,我们通过API与它沟通。 – Robodude 2012-02-12 01:41:44

0

也许你可以在.Where()之内拨打.Any()并完全跳过循环。

test.Groups.Where(x => (MileId == null || 
               x.Milestone == MileId) && 
               x.ProjectId == ProjectId && 
               ChartItems.Any(c => c.ChartStatusItems.Any(s => s.StatusId == x.StatusId && 
                s.ChartPriorityItems.Any(p => p.PriorityId == x.PriorityId))));