2009-10-12 5 views
5

J'ai un formulaire de recherche qui permet aux utilisateurs de chercher sur plusieurs champs différents de plusieurs façons différentes. Voici un exemple de mon code. J'ai une dizaine de champs différents sur lesquels un utilisateur peut effectuer une recherche afin que mon instruction switch externe soit assez grande. Il doit y avoir une manière plus élégante d'accomplir ceci.Formulaire de recherche ASP.NET - Linq to SQL dynamique?

Répondre

3

Vous pouvez factoriser certaines parties du code en créant une méthode d'extension. Quelque chose comme ça:

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

Vous pouvez alors l'utiliser comme ça:

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

Salut Thomas, votre solution ressemble beaucoup et il est très proche de ce que je cherche. Est-il sûr de définir le "revendications" var à la source de données d'un gridview? Je viens d'essayer et j'ai reçu un message d'erreur. –

+0

Désolé, le message d'erreur était: La méthode 'System.Object DynamicInvoke (System.Object [])' ne prend pas en charge la traduction vers SQL. –

+0

OK, je vois le problème ... Linq to SQL ne peut pas convertir un appel de délégué à une expression SQL, donc il échoue. Je vais essayer de trouver une solution et mettre à jour ma réponse –

0

Vous pouvez faire un dictionnaire de vos possibles prédicats:

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

qui pourrait être utilisé comme ceci:

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