2012-10-23 47 views
0

爲了簡單起見,讓我們假設我有以下兩類:建立一個查詢(LINQ)與一個子查詢

public class ComplexClass 
{ 
    public List<SubClass> SubClasses { get; set; } 
    public string Name { get; set; } 
} 

public class SubClass 
{ 
    public string Name { get; set; } 
} 

我有一個List<ComplexClass>,我需要建立基於某些參數的查詢。

如果我只需要使用ComplexClassName屬性,那麼這是一件容易的事。這裏有一個例子:

static IQueryable<ComplexClass> GetQuery(string someParameter, string someOtherParameter) 
    { 
     var query = list.AsQueryable(); 
     if (!String.IsNullOrEmpty(someParameter)) 
      query = query.Where(c => c.Name.StartsWith(someParameter)); 
     if (!String.IsNullOrEmpty(someOtherParameter)) 
      query = query.Where(c => c.Name.EndsWith(someOtherParameter)); 
     return query; 
    } 

基於我有我可以添加更多的查詢元素的參數。當然,上面的例子很簡單,但實際問題包含更多參數,並且該數字可能會增加。

事情並不那麼簡單,如果我想找到那些ComplexClass情況下具有​​情況下,符合基於參數標準:

static IQueryable<ComplexClass> GetSubQuery(string someParameter, string someOtherParameter) 
    { 
     var query = list.AsQueryable(); 
     if (!String.IsNullOrEmpty(someParameter)) 
      if (!String.IsNullOrEmpty(someOtherParameter)) 
       return query.Where(c => c.SubClasses.Where(sc => sc.Name.StartsWith(someParameter) && sc.Name.EndsWith(someOtherParameter)).Any()); 
      else 
       return query.Where(c => c.SubClasses.Where(sc => sc.Name.StartsWith(someParameter)).Any()); 
     else 
      if (!String.IsNullOrEmpty(someOtherParameter)) 
       return query.Where(c => c.SubClasses.Where(sc => sc.Name.EndsWith(someOtherParameter)).Any()); 
      else 
       return null; 
    } 

我可以不再僅僅添加基於每個參數的查詢位,我現在需要一次性寫完整個查詢,這意味着我需要檢查每個參數組合,這很不理想。

我懷疑關鍵是要建立一個Expression類,並創建一個lambda表達式,但我不知道如何解決這個問題。

有什麼建議嗎? :)

編輯:

我最初的想法是這樣的:

static IQueryable<ComplexClass> GetSubQuery(string someParameter, string someOtherParameter) 
    { 
     var query = list.AsQueryable(); 
     query = query.Where(c => 
     { 
      var subQuery = c.SubClasses.AsQueryable(); 
      if (!String.IsNullOrEmpty(someParameter)) 
       subQuery = subQuery.Where(sc => sc.Name.StartsWith(someParameter)); 
      if (!String.IsNullOrEmpty(someOtherParameter)) 
       subQuery = subQuery.Where(sc => sc.Name.EndsWith(someOtherParameter)); 
      return subQuery.Any(); 
     }); 
     return query; 
    } 

,因爲它是使用LINQ to對象本工作在我小的控制檯測試應用程序。不幸的是,我需要使用實體框架和LINQ to Entities,這導致類似於上面的實現拋出A lambda expression with a statement body cannot be converted to an expression tree錯誤消息。

+0

您正在使用「someParameter」和「someOtherParameter」只是爲了檢查它們是否爲空或不,實際上並沒有在哪裏使用條件,那麼它們的最終結果是什麼?它們似乎與案例有關...解釋更多... –

+0

您可以使用'.Any(。謂詞).Any() (謂詞)'。 –

+0

Amol:參數是可以爲空的,是的,但在實際的最終代碼中用於查詢。事實上,這些例子看起來有點愚蠢。我將編輯這些例子。丹尼爾:我知道,但那不僅僅是問題。 – Shaamaan

回答

1

我假設你在現實生活中的代碼SubClasses屬性是IQueryable<SubClass>而不是List<SubClass>

如果是這樣,那麼你的查詢構建變得容易:

static IQueryable<ComplexClass> GetSubQuery(
    string someParameter, string someOtherParameter) 
{ 
    var query = list.AsQueryable(); 
    if (!String.IsNullOrEmpty(someParameter)) 
     query = query.Where(c => c.SubClasses 
      .Where(sc => sc.Name.StartsWith(someParameter)).Any()); 
    if (!String.IsNullOrEmpty(someOtherParameter)) 
     query = query.Where(c => c.SubClasses 
      .Where(sc => sc.Name.StartsWith(someOtherParameter)).Any()); 
    return query; 
} 

使用AsQueryable()從來都不是一個好主意,混合IEnumerable<T>IQueryable<T>

+0

哦,親愛的......它是如此簡單,一直以來......> _ < 感謝一大堆! – Shaamaan

+0

等待...不會這樣(假設所有參數都不爲空)會導致查詢花費很長的時間來執行?我只是有一個想法,使用'SelectMany'創建一個子查詢,像第一個例子中的查詢那樣構建它,然後執行'query.Where(cc => cc.SubClasses.Where(sc => subQuery。包含(sc))。任何())'...這是行得通的,但我不確定哪一個更快(如果有的話)。 – Shaamaan

+0

@Shaamaan - 如果我是你,我不確定我會擔心速度,直到你確定自己有性能問題。即使它重複緩存將極大地加速第二個子查詢的子查詢,機會也是很好的。 – Enigmativity

0

我實現了我的一個簡單的控制檯項目的解決方案:

internal class Program 
{ 
    #region Constants and Fields 

    private static readonly List<ComplexClass> list = new List<ComplexClass> 
                  { 
                   new ComplexClass 
                    { 
                     Name = "complex", 
                     SubClasses = new List<SubClass> 
                         { 
                          new SubClass 
                           { 
                            SubName = "foobar" 
                           } 
                         } 
                    }, 
                   new ComplexClass 
                    { 
                     Name = "complex", 
                     SubClasses = new List<SubClass> 
                         { 
                          new SubClass 
                           { 
                            SubName = "notfoobar" 
                           } 
                         } 
                    } 
                  }; 

    #endregion 

    #region Public Methods 

    public static void Main(string[] args) 
    { 
     Console.WriteLine("foo/bar :"); 
     GetSubQuery("foo", "bar"); 
     Console.WriteLine(); 

     Console.WriteLine("foo/null :"); 
     GetSubQuery("foo", null); 
     Console.WriteLine(); 

     Console.WriteLine("string.Empty/bar :"); 
     GetSubQuery(string.Empty, "bar"); 
     Console.WriteLine(); 

     Console.WriteLine("maeh/bar :"); 
     GetSubQuery("maeh", "bar"); 

     Console.ReadKey(); 
    } 

    #endregion 

    #region Methods 

    private static void GetSubQuery(string startsWith, 
     string endsWith) 
    { 
     var query = from item in list 
        let StartIsNull = string.IsNullOrEmpty(startsWith) 
        let EndIsNull = string.IsNullOrEmpty(endsWith) 
        where 
         (StartIsNull || item.SubClasses.Any(sc => sc.SubName.StartsWith(startsWith))) 
         && (EndIsNull || item.SubClasses.Any(sc => sc.SubName.EndsWith(endsWith))) 
        select item; 

     foreach (var complexClass in query) 
     { 
      Console.WriteLine(complexClass.SubClasses.First().SubName); 
     } 
    } 

    #endregion 

    public class ComplexClass 
    { 
     #region Public Properties 

     public string Name { get; set; } 
     public List<SubClass> SubClasses { get; set; } 

     #endregion 
    } 

    public class SubClass 
    { 
     #region Public Properties 

     public string SubName { get; set; } 

     #endregion 
    } 
} 

控制檯輸出:

foo/bar : 
foobar 

foo/null : 
foobar 

string.Empty/bar : 
foobar 
notfoobar 

maeh/bar :