2009-12-18 5 views
1

Je souhaite créer une fenêtre de recherche générique en utilisant linq to sql.Dynamic Linq to SQL Query

C'est ce que je voulais faire:

class SearchWindow<T> : Form : Where T: class 
{ 
    public SearchWindow(Func<T, string> codeSelector, 
         Func<T, string> nameSelector) 
    { 
     var db = new DataContext(); 
     var table = db.GetTable<T>(); 
     var query = from item in table where 
         codeSelector(item).Contains(someText) && 
         nameSelector(item).Contains(someOtherText) 
        select item; 
    } 
} 

Et je suis en train de l'utiliser comme:

var searchWindow = new SearchWindow<SomeTable>(x => x.CodeColumn, 
               y => y.NameColumn).Show(); 

Bud saddly qui ne fonctionne pas, je lis sur les arbres d'expression si J'ai essayé de le faire avec eux, et je suis arrivé:

public SearchWindow(codeColumn, nameColumn) 
{ 
    Table<T> table = db.GetTable<T>(); 
    var instanceParameter = Expression.Parameter(typeof(T), "instance"); 
    var methodInfo = typeof(string).GetMethod("Contains", 
               new Type[] { typeof(string) }); 
    var codigoExpression = Expression.Call(Expression.Property(instanceParameter, 
               codeColumn), 
              methodInfo, 
              Expression.Constant("someText", 
               typeof(string))); 
    var nombreExpression = Expression.Call(Expression.Property(instanceParameter, 
               nameColumn), 
              methodInfo, 
              Expression.Constant("someOtherText", 
               typeof(string))); 
    var predicate = Expression.Lambda<Func<T, bool>>(
     Expression.And(codigoExpression, nombreExpression), instanceParameter); 
    var query = table.Where(predicate); 
} 

et pour l'utiliser je dois faire:

new SearchWindow<SomeTable>("codeColumn", "nameColumn"); 

Mais je n'aime pas l'approche nécessaire d'entrer les noms de colonnes en tant que chaîne, est-il possible de le faire d'une manière similaire à ma première approche (afin d'avoir IntelliSense et frappe fort) ?

Nous vous remercions de votre aide.

+0

Je pense que les pièces manquantes sont "Expression.Invoke" et "Expression.AndAlso"; J'ai essayé de montrer dans un exemple. –

Répondre

2

Untested, mais quelque chose comme:

static IQueryable<T> Search<T>(
     IQueryable<T> source, 
     Expression<Func<T, string>> codeSelector, 
     Expression<Func<T, string>> nameSelector, 
     string code, string name) 
    { 

     var row = Expression.Parameter(typeof(T), "row"); 
     var body = Expression.AndAlso(
      Expression.Call(
       Expression.Invoke(codeSelector, row), 
       "Contains", null, 
       Expression.Constant(code, typeof(string))), 
      Expression.Call(
       Expression.Invoke(nameSelector, row), 
       "Contains", null, 
       Expression.Constant(name, typeof(string)))); 
     var lambda = Expression.Lambda<Func<T, bool>>(body, row); 
     return source.Where(lambda); 
    } 

Vous passez votre table (GetTable<T>) comme source et lambdas pour indiquer les colonnes (x => x.CodeColumn/y => y.NameColumn etc).


Mise à jour; testé sur LINQ-à-objets, je suis plein d'espoir que ça va marcher sur LINQ to SQL ainsi:

 var data = new[] { 
      new { Code = "abc", Name = "def"}, 
      new { Code = "bcd", Name = "efg"}, 
      new { Code = "ghi", Name = "jkl"} 
     }.AsQueryable(); 

     var filtered = Search(data, x => x.Code, x => x.Name, "b", "f"); 
     var arr = filtered.ToArray(); 
+0

Cela fonctionne !, merci beaucoup – albertein