动态过滤linq lambda表达式

时间:2012-02-11 20:16:09

标签: c# linq

我目前正在尝试以下操作。

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访问它。

4 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分: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将如何与性能进行交互,但至少它简洁......)

答案 2 :(得分: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))

答案 3 :(得分:0)

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

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