web-dev-qa-db-fra.com

Réutilisation d'une requête LINQ

Il ne s’agit pas de la réutilisation d’un résultat, mais plutôt de la déclaration elle-même. Il ne s'agit pas non plus d'une erreur lors de l'utilisation de var, comme indiqué dans: LINQ to SQL: réutiliser l'expression lambda

Par pure curiosité, je me demandais s'il était possible de réutiliser un seul énoncé LINQ.

Disons que j'ai l'instruction LINQ suivante: 

.Where(x => x.Contains(""));

Est-il possible d'extraire l'instruction x => x.Contains("") et d'utiliser une sorte de référence à celle-ci pour une utilisation ultérieure dans, disons, une autre classe?

Donc, je peux l'appeler comme suit: .Where(previouslySavedStatement);

32
Blaatz0r

Vous pouvez le stocker dans une variable. Si vous travaillez avec IQueryable, utilisez:

System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains("");

Si vous utilisez IEnumerable, utilisez:

Func<Foo, bool> selector = x => x.Contains("");

Et utilisez-le dans votre requête:

query.Where(selector);
37
Hamid Pourjam

Oui, vous pouvez écrire une fonction contenant la requête que vous souhaitez réutiliser, qui prend et retourne un IQueryable <T>

   public IQueryable<T> ContainsEmpty(IQueryable<T> query)
   {
       return query.Where(x => x.Contains(""));
   }

Maintenant, vous pouvez le réutiliser:

   query1 = ContainsEmpty(query1);
   query2 = ContainsEmpty(another);
8
user1023602

Ça dépend. Il existe deux méthodes Where, Enumerable.Where et Queryable.Where. Si vous appliquez le .Where à une IEnumerable que la première est appelée, si vous l'appliquez à une IQueryable, le deuxième est appelé. 

Puisque Enumerable.Where prend dans une Func, elle n'est pas réutilisable. Puisque Queryable.Where prend une expression, celle-ci est réutilisable. Vous pouvez le faire comme suit:

var x = new List<string>().AsQueryable();

var query = x.Where (n => n.Contains("some string"));

//Extract the lambda clause
var expr = query.Expression;
var methodExpr = (MethodCallExpression)expr;
var quoteExpr = (UnaryExpression)methodExpr.Arguments[1];
var funcExpr = (Expression<Func<string, bool>>)quoteExpr.Operand;

Vous pouvez ensuite ré-appliquer plus tard l'expression où:

var query2 = x.Where(funcExpr);
5
Shlomo

J'ai écrit une bibliothèque pour traiter exactement ce problème, elle s'appelle CLink et vous pouvez trouver une implémentation pour EntityFramework ici: https://www.nuget.org/packages/CLinq.EntityFramework

Il permet de créer des extraits de requête et de les utiliser partout dans une requête linq. En suivant l'exemple de Hamid, créez l'expression suivante:

System.Linq.Expressions.Expression<Func<Foo, bool>> selector = x => x.Contains("");

Vous pouvez maintenant utiliser cette requête partout dans vos requêtes linq comme ceci:

query.AsComposable().Where(o => selector.Pass(o));

En plus de cet exemple simple, vous pouvez également combiner vos extraits de requête:

query.AsComposable().Where(o => selector.Pass(o) || anotherSelector.Pass(o));

ou même les fusionner:

query.AsComposable().Where(o => anotherSelector.Pass(selector.Pass(o)));

Il y a quelques fonctionnalités supplémentaires, mais je pense que c'est vraiment utile, alors jetez-y un coup d'œil :)

0
crazy_crank