2011-11-21 53 views
4

讓我們假設我們需要在實體列表上進行查詢,並且我們不知道那些非常動態的標準,並且實體內部有字典和簡單字段讓這是下一個實體 - 地址(爲簡單起見,我只留下了一個屬性)。動態編譯LINQ查詢以驗證字典值

public class Address 
{ 
    #region Public members 

    /// <summary> 
    /// The extra datafield values 
    /// </summary> 
    public IDictionary<string, string> DataFieldValues { get; set; } 

    public string City { get; set; } 

    #endregion 
} 

現在,如果我們查詢名爲固定字段時,我得到了實現:

private static Expression<Func<Address, bool>> BuildLambdaForAQueryItem(string caption, string value) 
     { 
      ParameterExpression param = Expression.Parameter(typeof(Address), caption); 
      BinaryExpression body = Expression.Equal(Expression.PropertyOrField(param, caption), 
                Expression.Constant(value, 
                     typeof(Address).GetProperty(
                      caption).PropertyType)); 
      return Expression.Lambda<Func<Address, bool>>(body, param); 
     } 

現在,如果我想在DataFieldValue coolection查詢我需要寫一個lambda也類似:

x => x.DataFieldValues.ContatinsKey(key)& & DataFieldValues [key] = =值 我得到下面的方法幾乎similar但仍不適正確的過濾器:在兩個謂語表達式

private static Expression<Func<Address, bool>> BuildLambdaForAnExtraField(PostedQueryItem queryItem) 
{ 
    ParameterExpression dataFields = Expression.Parameter(typeof(Address), "x"); 
    var dictionaryExpression = Expression.PropertyOrField(dataFields, "DataFieldValues"); 
    var keyExists = Expression.Call(dictionaryExpression, "ContainsKey", null, Expression.Constant(queryItem.Caption)); 

    Expression dictionaryAccessExpr = Expression.Property(dictionaryExpression, "Item", 
                  Expression.Constant(queryItem.Caption)); 
    var valueCorresponds = Expression.Equal(dictionaryAccessExpr, Expression.Constant(queryItem.Value)); 

    return Expression.Lambda<Func<Address, bool>>(keyExists, dataFields).And(
     Expression.Lambda<Func<Address, bool>>(valueCorresponds, dataFields)); 
} 

回答

2

我想你想使用Expression.AndAlso(短路AND)有問題構建表達式樹的主體。

var body = Expression.AndAlso(keyExists, valueCorresponds); 
return Expression.Lambda<Func<Address, bool>>(body, dataFields); 

編輯:(如果你想與您現有的技術貼)

我的猜測是,你And方法是從LINQKit庫擴展法。如果是這樣,請注意,此擴展涉及使用第一個表達式的參數「調用」右側表達式,作爲生成結果的一部分。如果你不接受這種情況(LINQ提供商的限制,或許?),你可以使用該庫附帶的有用的Expand擴展名來「內聯」調用的表達式。

return Expression.Lambda<Func<Address, bool>>(keyExists, dataFields) 
       .And(Expression.Lambda<Func<Address, bool>>(valueCorresponds, dataFields)) 
       .Expand(); 

但是,這是在這種情況下大規模矯枉過正;我的建議是去我的第一個樣本。

+0

你說得對,謝謝。但我仍然不明白爲什麼我以前的實現沒有解決 –

+0

@Hohhi:我已經編輯了一個解決方案。 – Ani

+0

感謝您提供快速而全面的幫助 –