2012-02-11 172 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))));