2012-05-17 109 views
1

代碼:有沒有辦法改進這個LINQ?

IList<Evento> Eventi = new List<Evento>() { }; 

Eventi = (from Evento ae in new Eventi() 
      select ae).ToList(); 

if (strNome != "") 
{ 
    Eventi = Eventi.Where(e => e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "").ToList(); 
} 

if (strComune != "") 
{ 
    Eventi = Eventi.Where(e => e.Comune != null && e.IDComune == strComune).ToList(); 
} 

if (strMesi != "") 
{ 
    Eventi = Eventi.Where(e => MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString())).ToList(); 
} 

我知道所有的查詢合併,運行的代碼時,只有1 LINQ語句中。但是,正如你所看到的,我多次轉換List - > ToList()。我認爲這是我浪費時間的唯一部分,對吧?我該如何避免這種情況並提高性能?

+0

當你投了集合列出你基本上獲取iqueryable列表。如果您不直接投射,則需要提供結果,您應該重新執行查詢 – cpoDesign

回答

4

爲什麼這麼多列表/ ToLists? IEnumerable/IQueryable出了什麼問題?

var eventi = (from Evento ae in new Eventi() 
      select ae); 

if (strNome != "") 
{ 
    eventi = eventi.Where(e => e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != ""); 
} 

if (strComune != "") 
{ 
    eventi = eventi.Where(e => e.Comune != null && e.IDComune == strComune); 
} 

if (strMesi != "") 
{ 
    eventi = eventi.Where(e => MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString())); 
} 

// if you do need a list, then do so right at the end 
var results = eventi.ToList(); 

編輯:爲了澄清一些原則Caesay

Caesay,感謝您抽出寶貴的時間來測試執行確認延遲加載按預期工作;很多榮譽!

我想解釋一下爲什麼要與你的上述做法是在運行時而你是在編譯時優化優化評論不同意。

上面的方法是,由於缺少更好的描述,打算使用的方法。這是因爲對甚至的分配正確地將表達式附加到IEnumerable/IQueryable的

只有某些提供商(如Linq to Entities)支持您的方法,這些提供商希望將Func(Of T, TResult)傳遞給它們的SelectWhere等擴展。許多提供者(如實體框架和Linq to Sql提供者)提供IQueryable,它們實現了IEnumerable。然而,這裏的區別在於,IQueryableSelectWhere等,期望您通過Expression(Of Func(Of T, TResult))

在這些情況下,您的代碼不會像預期的那樣行爲(或至少如我所料),因爲Expression不支持多行lambda,因爲編譯器會正確解釋我的語句並將它們編譯爲Expression>。

作爲一個簡單的例子:

public void Test<T1, T2>(System.Linq.Expressions.Expression<Func<T1, T2>> arg) 
{ 
    throw new NotImplementedException(); 
} 

public void Test() 
{ 
    Test((string x) => x.ToLower()); 
    Test((string x) => 
    { 
     return x.ToLower(); 
    }); 
} 

在上述例子中,第一個表達式是絕對優良。第二,這是鬆散的基礎上你的榜樣,將失敗,異常:

A lambda expression with a statement body cannot be converted to an expression tree 

編譯器可以識別您的語句作爲Func鍵它知道被支持的IEnumerable。結果將是對數據庫的查詢不會包含任何Where表達式,並返回整個數據源。一旦數據源在內存中,它就會應用您的IEnumerable Where子句。就個人而言,我更喜歡將這些東西傳遞給數據庫,這樣我就不會浪費帶寬返回比我需要的數據更多的數據,並且我可以利用數據源功能來過濾可能(並且很大程度上在Sql Server的情況)比在內存中更好。

我希望這是有道理的,對您有用嗎?

+0

,這樣第一行中的「var」就像IEnumerable。我怎樣才能聲明一個空的可枚舉? – markzzz

+0

因爲它處於foreach循環。 'Enumerable.Empty ();'? – markzzz

+0

對不起@markzzz的慢回覆。你使用_var_聲明一個變量,從變量中推斷出它是類型的,否則稱爲隱式聲明:http://msdn.microsoft.com/en-us/library/bb383973.aspx – Smudge202

0

您可以使用流暢的語法開頭(避免列表)。

或者,您可以在一個查詢中組合條件。

Eventi =(new Eventi()).Where(e => e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "" && e.Comune != null && e.IDComune == strComune &&MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString())).ToList(); 

我假設節慶活動實現IEnumerable <事件摘要>如您在查詢語法同樣使用

+0

我喜歡單行遊戲,但是我覺得這種方法很難閱讀。也許你可以保持單線程的方法,但在_.Where_和_ && _之前添加新行,以便將其分解爲邏輯塊? – Smudge202

+0

我也喜歡一行,但是當一些謂詞變長時,我更喜歡在不同的行中分割,或者使用命名方法(而不是匿名方法) – Tilak

0

既然你測試strNome不是空的,你的第一個下半年Where子句將永遠不會被調用。

所以e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "" 可以寫e.Titolo.ToLower().Contains(strNome.ToLower())

你也可以計算strNome.ToLower()拉姆達外面,以確保它被計算一次。

此外,您可以簡化Where子句並刪除ToList(),正如其他人所建議的那樣。

另一種選擇,你應該知道的是LinqKit它允許你lambda表達式更容易這雖然因爲Where ... Where在這種情況下並不需要是一個足夠好的「和」結合起來,你也許有一天會需要一個「或」和那麼你需要不同的解決方案。

或者更好,但使用的方法解釋here創建執行表達自己AndOr方法「魔力」給你一個單一的表達,你可以移交給LINQ到SQL或任何其他LINQ提供程序。

0

結合整個事情到1個LINQ查詢是這樣的:

 var eventi = from Evento e in new Eventi() select e; 

     eventi = eventi.Where(e => 
     { 
      if (strNome != "") 
      { 
       if(!(e.Titolo.ToLower().Contains(strNome.ToLower()) && e.Titolo != "")) 
        return false; 
      } 
      if (strComune != "") 
      { 
       if(!(e.Comune != null && e.IDComune == strComune)) 
        return false; 
      } 
      if (strMesi != "") 
      { 
       if(!(MesiSelezionati.Contains(DateTime.Parse(e.DataEvento).Month.ToString()))) 
        return false; 
      } 

      return true; 
     }); 

     var results = eventi.ToList(); 

這是邏輯上等同於你的代碼,但是要快很多。雖然我無法測試它,因爲我無法編譯它。

+0

它不是一個exlusive if/else。只有如果...如果...如果... :) – markzzz

+0

我的錯誤 - 它已更新。 – caesay

+0

我認爲Smudge202的答案更快/更具可讀性? – markzzz