2014-11-05 68 views
3

我在我的應用程序中有一個方法,它需要根據一組條件讀取,篩選和提供數據。 我試圖使用LINQ來實現:如何動態地構建/更改LINQ語句的一部分

var pipelineData = from data in new XPQuery<AccountView3.PipelineData>(uow) 
     where data.Stage.ToLower().Contains("won") 
     && data.RevenueStartDate.Value.Year == DateTime.Today.Year 
     && data.WeekOfTheYear >= priorWeekCutoff 
     && (!string.IsNullOrEmpty(data.PlatformTcv) && data.PlatformTcv != "#N/A") 
     select data; 

就其本身而言,這工作得很好。問題是 - 根據正在傳遞的搜索條件,而不是data.PlatformTvc它可能是data.WorkspaceTvc,或data.Cyber​​Tvc等...我不知道哪種可能需要評估5個選擇。

我的問題是:有沒有辦法以這種方式構建LINQ語句,部分語句是有條件執行的。因此,如果用戶通過「平臺」作爲搜索條件,則LINQ語句將讀取... string.IsNullOrEmpty(data.PlatformTcv),但是如果條件是「Cyber​​」,則該LINQ語句應該讀取... string.IsNullOrEmpty(data.CyberTcv) 有沒有辦法實現這一點?

回答

9

當然。利用LINQ推遲執行模型並將可變謂詞嵌入到查詢中。例如:

Func<DataObject, string> accessor = data => data.PlatformTcv; 

var pipelineData = from data in new XPQuery<AccountView3.PipelineData>(uow) 
        where data.Stage.ToLower().Contains("won") 
         && data.RevenueStartDate.Value.Year == DateTime.Today.Year 
         && data.WeekOfTheYear >= priorWeekCutoff 
         && (!string.IsNullOrEmpty(accessor(data)) 
         && accessor(data) != "#N/A") 
        select data; 

var basedOnPlatform = pipelineData.ToArray(); 

accessor = data => data.CyberTV; 

var basedOnCyber = pipelineData.ToArray(); 

(這是假設查詢元素類型是DataObject當然,你會替換成你使用任何類型的實際名稱)。

只要記住這會讓LINQ更難理解,並且始終記住查詢的延遲執行性質。即如果它們沒有像某些其他集合那樣「物化」(例如,調用ToArray()),則在下次執行基礎查詢時將顯示更改。

+0

現在要試試這個... – 2014-11-05 22:46:58

+0

這是天才!謝謝! – 2014-11-05 23:30:57

2

您可以爲這是對所有查詢相同的部分創建一個IQueryable:

var pipelineData = from data in new XPQuery<AccountView3.PipelineData>(uow) 
    where data.Stage.ToLower().Contains("won"); 
    // etc 

然後應用特定的過濾器:

if (somecondition) 
{ 
    pipelineData = pipelineData.Where(x => x.SomeField == "somevalue"); 
} 
// etc 
+0

小心。 OP_might_想要重用原始查詢(對於我來說不完全清楚),因此您可能不想將新的過濾版本分配回原始變量。值得注意的是,至少在最初的例子中,這個解決方案可能比我提供的解決方案更具可讀性,更易於維護。它不會推廣到LINQ查詢的其他元素,但恕我直言,如果您只是進行過濾,這是一個非常好的選擇。 – 2014-11-05 23:04:29

+0

我完全同意。 – 2014-11-05 23:05:24