2009-10-12 125 views
5

我有一個搜索表單,允許用戶以幾種不同的方式搜索幾個不同的字段。這是我的代碼的一個例子。ASP.NET搜索表單 - 動態Linq to SQL?

var claims = from c in db.Claims select c; 

switch (ddlSearchField.Text) 
{ 
    case "StartsWith": 
     claims = claims.Where(c => c.companyFileID.StartsWith(txtSearchBox.Text)); 
     break; 

    case "Equals": 
     claims = claims.Where(c => c.companyFileID == txtSearchBox.Text); 
     break; 

    case "Contains": 
     claims = claims.Where(c => c.companyFileID.Contains(txtSearchBox.Text)); 
     break; 
} 

我有十個不同的領域,用戶可以搜索,所以我外面的開關語句是相當大的。必須有一個更優雅的方式來完成這一點。

回答

3

您可以通過創建重構代碼的某些部分一種擴展方法。類似的東西:

static class QueryableExtensions 
{ 
    private static MethodInfo StringContainsMethod; 
    private static MethodInfo StringStartsWithMethod; 

    static QueryableExtensions() 
    { 
     Type[] singleStringParam = new[] {typeof(string)}; 
     StringContainsMethod = typeof(string).GetMethod("Contains", singleStringParam); 
     StringStartsWithMethod = typeof(string).GetMethod("StartsWith", singleStringParam); 
    } 

    public static IQueryable<T> AppendTextFilter<T>(this IQueryable<T> queryable, Expression<Func<T, string>> memberSelector, string condition, string value) 
    { 
     Expression expression = null; 
     switch (condition) 
     { 
      case "StartsWith": 
       expression = Expression.Call(
           memberSelector.Body, 
           StringStartsWithMethod, 
           Expression.Constant(value)); 
       break; 

      case "Equals": 
       expression = Expression.Equal(
           memberSelector.Body, 
           Expression.Constant(value)); 
       break; 

      case "Contains": 
       expression = Expression.Call(
           memberSelector.Body, 
           StringContainsMethod, 
           Expression.Constant(value)); 
       break; 

      default: 
       throw new NotSupportedException(string.Format("'{0}' is not a supported condition", condition)); 
     } 

     var lambda = Expression.Lambda<Func<T, bool>>(
         expression, 
         memberSelector.Parameters); 
     return queryable.Where(lambda); 
    } 
} 

然後,您可以使用它像:

var claims = db.Claims 
      .AppendTextFilter(c => c.companyFileID, ddlSearchField.Text, txtSearchBox.Text) 
      .AppendTextFilter(c => c.someOtherProperty, ddlOtherSearchField.Text, txtOtherSearchBox.Text) 
      ...; 
+0

喜托馬斯,您的解決方案看起來不錯,這是非常接近我所期待的。將「聲明」var設置爲gridview的數據源安全嗎?我剛剛嘗試過,並收到錯誤消息。 – 2009-10-12 21:14:33

+0

對不起,該錯誤消息爲: 方法 'System.Object的DynamicInvoke(System.Object的[])' 無支持轉換爲SQL。 – 2009-10-12 21:25:37

+0

好的,我看到了問題... Linq to SQL無法將委託調用轉換爲SQL表達式,因此失敗。我會盡力找到解決方案並更新我的答案 – 2009-10-12 22:22:02

0

你可以讓你的可能謂詞的詞典:

Dictionary<string, Func<string, Expression<Func<Claim, bool>>>> map = new Dictionary<string, Func<string, Expression<Func<Claim, bool>>>>() { 
    { "StartsWith", t => c => c.companyFileID.StartsWith(t) }, 
    { "Equals",  t => c => c.companyFileID == t }, 
    { "Contains", t => c => c.companyFileID.Contains(t) } 
}; 

哪位能像這樣被使用:

var search = ddlSearchField.Text; 
var text = txtSearchBox.Text; 

var claims = from c in db.Claims select c; 

Func<string, Expression<Func<Claim, bool>>> predicate = null; 
if(dict.TryGetValue(search, out predicate)) 
    claims = claims.Where(predicate(text));