2

(EDIT: J'ai posé la mauvaise question.Le réel problème que j'ai est à Compose LINQ-to-SQL predicates into a single predicate - mais celui-ci a eu de bonnes réponses, donc j'ai laissé it up)récursivement (?) Composer LINQ prédicats dans un seul prédicat

Compte tenu du texte de recherche suivant:

"keyword1 keyword2 keyword3 ... keywordN" 

Je veux finir avec l'instruction SQL suivante:

SELECT [columns] FROM Customer 
    WHERE 
    (Customer.Forenames LIKE '%keyword1%' OR Customer.Surname LIKE '%keyword1%') 
    AND 
    (Customer.Forenames LIKE '%keyword2%' OR Customer.Surname LIKE '%keyword2%') 
    AND 
    (Customer.Forenames LIKE '%keyword3%' OR Customer.Surname LIKE '%keyword3%') 
    AND 
    ... 
    AND 
    (Customer.Forenames LIKE '%keywordN%' OR Customer.Surname LIKE '%keywordN%') 

E ffectivement, nous divisons le texte de recherche sur les espaces, découpons chaque jeton, construisons une clause OR à plusieurs parties basée sur chaque jeton, puis ET'ing ensemble les clauses. Je le fais dans Linq-to-SQL, et je n'ai aucune idée de la façon de composer dynamiquement un prédicat basé sur une liste arbitrairement longue de sous-prédicats. Pour un certain nombre de clauses connu, il est facile de composer les prédicats manuellement:

dataContext.Customers.Where(
    (Customer.Forenames.Contains("keyword1") || Customer.Surname.Contains("keyword1") 
    && 
    (Customer.Forenames.Contains("keyword2") || Customer.Surname.Contains("keyword2") 
    && 
    (Customer.Forenames.Contains("keyword3") || Customer.Surname.Contains("keyword3") 
); 

mais je veux gérer une liste arbitraire de termes de recherche. Je suis aussi loin que

Func<Customer, bool> predicate = /* predicate */; 
foreach(var token in tokens) { 
    predicate = (customer 
     => predicate(customer) 
     && 
     (customer.Forenames.Contains(token) || customer.Surname.Contains(token)); 
} 

qui produit une StackOverflowException - probablement parce que le prédicat() sur la partie droite de l'affectation n'est pas évalué avant l'exécution, à quel point il finit par se faisant appeler ... ou quelque chose . En bref, j'ai besoin d'une technique qui, avec deux prédicats, retournera un seul prédicat composant les deux prédicats source avec un opérateur fourni, mais limité aux opérateurs explicitement supportés par Linq-to-SQL. Des idées?

+0

@KennyTM - je ne sais pas ce que vous voulez dire ... pouvez-vous élaborer (s'il vous plaît)? –

Répondre

3

Je suggère une autre technique

vous pouvez faire:

var query = dataContext.Customers; 

puis, à l'intérieur d'un cycle ne

foreach(string keyword in keywordlist) 
{ 
    query = query.Where(Customer.Forenames.Contains(keyword) || Customer.Surname.Contains(keyword)); 
} 
+0

Bien sûr ... quand vous le mettez comme ça, il semble si simple :) Génial. Je vous remercie. –

+0

D'oh. J'ai posé la mauvaise question. Jetez un oeil à http://stackoverflow.com/questions/3782940/compose-linq-to-sql-predicates-into-a-single-predicate pour ce que j'essaie vraiment de réaliser. Oops. –

1

Si vous voulez une manière plus succincte et déclarative d'écrire ce , vous pouvez également utiliser la méthode d'extension Aggregate au lieu de foreach boucle et variable mutable:

var query = keywordlist.Aggregate(dataContext.Customers, (q, keyword) => 
    q.Where(Customer.Forenames.Contains(keyword) || 
      Customer.Surname.Contains(keyword)); 

Cela prend dataContext.Customers comme l'état initial puis met à jour cet état (requête) pour chaque mot-clé dans la liste en utilisant la fonction d'agrégation donnée (qui appelle simplement Where comme le suggère Gnomo.