Linq correct où les clauses

J’écris pas mal de linq dans ma vie de tous les jours, mais surtout des déclarations simples. J’ai remarqué que lors de l’utilisation de clauses where, il y a plusieurs façons de les écrire et chacune a les mêmes résultats, autant que je sache. Par exemple;

from x in Collection where x.Age == 10 where x.Name == "Fido" where x.Fat == true select x; 

Semble être équivalent à cela au moins en ce qui concerne les résultats:

 from x in Collection where x.Age == 10 && x.Name == "Fido" && x.Fat == true select x; 

Alors, y a-t-il vraiment une différence autre que la syntaxe? Si oui, quel est le style préféré et pourquoi?

Le second serait plus efficace car il ne dispose que d’un prédicat à évaluer par rapport à chaque élément de la collection où, comme dans le premier, il applique d’abord le premier prédicat à tous les éléments et le résultat (réduit à ce stade) est utilisé pour le deuxième prédicat et ainsi de suite. Les résultats sont réduits à chaque passage mais cela implique encore plusieurs passes.

Le chaînage (première méthode) ne fonctionnera que si vous utilisez vos prédicats. Quelque chose comme ça x.Age == 10 || x.Fat == true x.Age == 10 || x.Fat == true ne fonctionnera pas avec votre première méthode.

EDIT: LINQ to Objects ne se comporte pas comme je l’avais prévu. Vous pouvez très bien être intéressé par le blog que je viens d’écrire à ce sujet …


Ils sont différents en termes de ce qui sera appelé – le premier est équivalent à:

 Collection.Where(x => x.Age == 10) .Where(x => x.Name == "Fido") .Where(x => x.Fat == true) 

lorsque ce dernier est équivalent à:

 Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true) 

Maintenant, quelle différence cela fait réellement dépend de l’implémentation de Where être appelé. Si c’est un fournisseur basé sur SQL, je m’attendrais à ce que les deux finissent par créer le même SQL. Si c’est dans LINQ to Objects, le second aura moins de niveaux d’indirection (il n’y aura que deux iterators au lieu de quatre). La question de savoir si ces niveaux d’indirection sont importants en termes de vitesse est une autre affaire.

Généralement, j’utiliserais plusieurs clauses where si elles semblent représenter des conditions significativement différentes (par exemple, l’une concerne une partie d’un object, l’autre est complètement séparée) et une autre where plusieurs conditions sont étroitement liées (par exemple, une valeur particulière est supérieure à un minimum et inférieure à un maximum). Fondamentalement, cela vaut la peine de considérer la lisibilité avant toute légère différence de performance.

Le premier sera mis en œuvre:

 Collection.Where(x => x.Age == 10) .Where(x => x.Name == "Fido") // applied to the result of the previous .Where(x => x.Fat == true) // applied to the result of the previous 

Par opposition au beaucoup plus simple (et beaucoup plus rapide sans doute plus rapide):

 // all in one fell swoop Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true) 

quand je cours

 from c in Customers where c.CustomerID == 1 where c.CustomerID == 2 where c.CustomerID == 3 select c 

et

 from c in Customers where c.CustomerID == 1 && c.CustomerID == 2 && c.CustomerID == 3 select c customer table in linqpad 

contre ma table client, il affiche la même requête SQL

 -- Region Parameters DECLARE @p0 Int = 1 DECLARE @p1 Int = 2 DECLARE @p2 Int = 3 -- EndRegion SELECT [t0].[CustomerID], [t0].[CustomerName] FROM [Customers] AS [t0] WHERE ([t0].[CustomerID] = @p0) AND ([t0].[CustomerID] = @p1) AND ([t0].[CustomerID] = @p2) 

donc en traduction vers SQL il n’y a pas de différence et vous avez déjà vu dans d’autres réponses comment ils seront convertis en expressions lambda

En regardant sous le capot, les deux instructions seront transformées en différentes représentations de requête. Selon le QueryProvider de Collection , cela peut être optimisé ou non.

Lorsqu’il s’agit d’un appel linq-to-object, plusieurs clauses where conduisent à une chaîne d’IEnumerables qui se lisent les unes les autres. Utiliser le formulaire de clause unique aidera les performances ici.

Lorsque le fournisseur sous-jacent le traduit en une instruction SQL, il est probable que les deux variantes créent la même instruction.