2009-10-12 19 views
5

Tôi có một mẫu tìm kiếm cho phép người dùng tìm kiếm trên nhiều lĩnh vực khác nhau theo nhiều cách khác nhau. Đây là một ví dụ về mã của tôi.Mẫu tìm kiếm ASP.NET - LINQ động cho 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; 
} 

Tôi có khoảng 10 trường khác nhau mà người dùng có thể tìm kiếm để câu lệnh chuyển đổi ngoài của tôi khá lớn. Phải có một cách thanh lịch hơn để thực hiện điều này.

Trả lời

3

Bạn có thể cấu trúc lại một số bộ phận của mã bằng cách tạo một phương pháp mở rộng. Một cái gì đó như thế:

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); 
    } 
} 

Sau đó, bạn có thể sử dụng nó như thế:

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

Hi Thomas, giải pháp của bạn trông tuyệt vời và nó rất gần với những gì tôi đang tìm kiếm. Có an toàn để đặt var "claim" thành nguồn dữ liệu của GridView không? Tôi vừa thử và nhận được một thông báo lỗi. –

+0

Xin lỗi, thông báo lỗi là: Phương thức 'System.Object DynamicInvoke (System.Object [])' không có bản dịch được hỗ trợ cho SQL. –

+0

OK, tôi thấy sự cố ... LINQ to SQL không thể chuyển đổi cuộc gọi đại biểu thành biểu thức SQL, do đó, nó không thành công. Tôi sẽ cố gắng tìm một giải pháp và cập nhật câu trả lời của tôi –

0

Bạn có thể làm một cuốn từ điển của các vị từ có thể bạn:

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) } 
}; 

Mà có thể được sử dụng như thế này:

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)); 
Các vấn đề liên quan