web-dev-qa-db-fra.com

Quel est l'aspect le plus difficile ou le plus incompris de LINQ?

Contexte: Au cours du mois prochain, je donnerai trois conférences sur ou au moins incluant LINQ dans le contexte de C#. J'aimerais savoir quels sujets méritent de retenir beaucoup d'attention, en fonction de ce que les gens peuvent trouver difficile à comprendre ou de ce qu'ils peuvent avoir une fausse impression. Je ne parlerai pas spécifiquement de LINQ à SQL ou d'Entity Framework, sauf à titre d'exemple de la manière dont les requêtes peuvent être exécutées à distance à l'aide d'arbres d'expression (et généralement IQueryable).

Alors, qu'est-ce que vous avez trouvé dur à propos de LINQ? Qu'avez-vous vu en termes de malentendus? Les exemples peuvent être les suivants, mais ne vous limitez pas vous-même!

  • Comment le C# le compilateur traite les expressions de requête
  • Expressions lambda
  • Arbres d'expression
  • Méthodes d'extension
  • Types anonymes
  • IQueryable
  • Exécution différée vs exécution immédiate
  • Streaming vs exécution en mémoire tampon (par exemple, OrderBy est différé mais en mémoire tampon)
  • Variables locales implicitement typées
  • Lecture de signatures génériques complexes (par exemple, Enumerable.Join )
282
Jon Skeet

Exécution différée

271
JaredPar

Je sais que le concept d’exécution différée devrait maintenant être intégré à moi, mais cet exemple m’a vraiment aidé à en saisir concrètement le sens:

static void Linq_Deferred_Execution_Demo()
{
    List<String> items = new List<string> { "Bob", "Alice", "Trent" };

    var results = from s in items select s;

    Console.WriteLine("Before add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }

    items.Add("Mallory");

    //
    //  Enumerating the results again will return the new item, even
    //  though we did not re-assign the Linq expression to it!
    //

    Console.WriteLine("\nAfter add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

Le code ci-dessus renvoie ce qui suit:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory
125
DSO

Qu'il y a plus que LINQ à SQL et que les fonctionnalités ne sont pas seulement un analyseur SQL incorporé dans le langage.

104
smaclell

notation Big O . LINQ facilite énormément l'écriture d'algorithmes O (n ^ 4) sans s'en rendre compte, si vous ne savez pas ce que vous faites.

86
erikkallen

Je pense que le fait qu'une expression Lambda puisse être résolue à la fois par une arborescence d'expression et par un délégué anonyme, vous pouvez donc transmettre la même expression déclarative lambda à la fois IEnumerable<T> méthodes d'extension et IQueryable<T> méthodes d'extension.

55
Tim Jarvis

Cela m'a pris chemin trop longtemps pour comprendre que de nombreuses méthodes d'extension LINQ telles que Single(), SingleOrDefault() etc. ont des surcharges qui prennent lambdas.

Tu peux faire :

Single(x => x.id == id)

et je n'ai pas besoin de le dire - ce que certains mauvais tutoriels m'ont fait prendre l'habitude de faire

Where(x => x.id == id).Single()
53
Simon_Weaver

Dans LINQ to SQL, je vois constamment des personnes ne comprenant pas le DataContext, comment il peut être utilisé et comment il devrait être utilisé. Trop de personnes ne voient pas le DataContext pour ce qu'il est, un objet Unit of Work, pas un objet persistant.

J'ai souvent vu des personnes essayer de singleton un DataContext/session it/etc plutôt que de créer une nouvelle heure pour chaque opération.

Et puis, il y a l'élimination du DataContext avant l'évaluation d'IQueryable, mais c'est plus un problème pour les personnes qui ne comprennent pas IQueryable que le DataContext.

L'autre concept avec lequel je vois beaucoup de confusion est la syntaxe requête/syntaxe d'expression. Je vais utiliser celui qui est le plus facile à ce stade, en m'appuyant souvent sur la syntaxe d'expression. Beaucoup de gens ne réalisent toujours pas qu'ils produiront la même chose à la fin, Query est compilé dans Expression après tout.

40
Aaron Powell

Je pense que la la partie mal comprise de LINQ est que c'est un extension de langue, pas une extension de base de données ni une construction.

LINQ est tellement plus que LINQ to SQL.

Maintenant que la plupart d'entre nous ont utilisé LINQ sur des collections, nous n'y retournerons JAMAIS!

LINQ est la fonctionnalité la plus importante pour .NET depuis Generics dans la version 2.0 et les types anonymes dans la version 3.0.

Et maintenant que nous avons Lambda, je ne peux pas attendre pour la programmation parallèle!

34
Chris

Pour ma part, j'aimerais bien savoir si j'ai besoin de savoir ce que sont les arbres d'expression, et pourquoi.

26
Robert Rossney

Je suis assez nouveau pour LINQ. Voici les choses que j'ai trébuché dans ma première tentative

  • Combinaison de plusieurs requêtes en une seule
  • Débogage efficace des requêtes LINQ dans Visual Studio.
20
Mark Heath

Quelque chose que je n'avais pas compris à l'origine était que la syntaxe LINQ non nécessite IEnumerable<T> ou IQueryable<T> pour fonctionner, LINQ n’est qu’une correspondance de motif.

alt text http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Voici la réponse (non, je n'ai pas écrit ce blog, Bart De Smet l'a fait, et il est l'un des meilleurs blogueurs sur LINQ que j'ai trouvés).

20
Aaron Powell

J'ai toujours des problèmes avec les commandes "let" (pour lesquelles je n'ai jamais trouvé d'utilisation) et SelectMany (que j'ai utilisées, mais je ne suis pas sûr de l'avoir bien fait)

19
James Curran

Comprendre quand l'abstraction chez les fournisseurs Linq fuit. Certaines choses fonctionnent sur des objets mais pas sur SQL (par exemple, .TakeWhile). Certaines méthodes peuvent être traduites en SQL (ToUpper), d’autres pas. Certaines techniques sont plus efficaces dans les objets où d'autres sont plus efficaces en SQL (méthodes de jointure différentes).

19
denis phillips

Un couple de choses.

  1. Les gens qui envisagent Linq comme Linq to SQL.
  2. Certaines personnes pensent qu'elles peuvent commencer à remplacer toutes les requêtes foreach/logic par des requêtes Linq sans tenir compte de ces implications en termes de performances.
12
Krishna Kumar

OK, à cause de la demande, j'ai rédigé certains des éléments d'Expression. Je ne suis pas entièrement satisfait de la façon dont Blogger et LiveWriter ont conspiré pour le formater, mais ça ira pour le moment ...

Quoi qu'il en soit, voici ... Je serais ravi de recevoir vos commentaires, surtout s'il y a des endroits où les gens veulent plus d'informations.

Le voici , aime ou déteste ça ...

11
Marc Gravell

Certains messages d'erreur, en particulier de LINQ à SQL, peuvent être assez déroutants. sourire

L'exécution différée m'a mordue à plusieurs reprises, comme tout le monde. Je pense que la chose la plus déroutante pour moi a été le fournisseur de requêtes SQL Server et ce que vous pouvez et ne pouvez pas faire avec.

Je suis toujours étonné par le fait que vous ne pouvez pas faire de Sum () sur une colonne décimale/argent qui est parfois vide. L'utilisation de DefaultIfEmpty () ne fonctionnera tout simplement pas. :(

10

Je pense qu’une bonne chose à couvrir dans LINQ est de savoir comment vous pouvez vous mettre en difficulté sur le plan des performances. Par exemple, utiliser le nombre de LINQ comme condition de boucle n'est vraiment pas très intelligent.

9
Steve

Que IQueryable accepte les deux, Expression<Func<T1, T2, T3, ...>> et Func<T1, T2, T3, ...>, sans donner d'indication sur la dégradation des performances dans le 2e cas.

Voici un exemple de code montrant ce que je veux dire:

[TestMethod]
public void QueryComplexityTest()
{
    var users = _dataContext.Users;

    Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
    Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");

    // Returns IEnumerable, and do filtering of data on client-side
    IQueryable<User> func = users.Where(funcSelector).AsQueryable();
    // Returns IQuerible and do filtering of data on server side
    // SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
    IQueryable<User> exp = users.Where(expressionSelector);
}
7
Valera Kolupaev

Je dirais que l'aspect le plus mal compris (ou devrait-il être incompris?) De LINQ est IQueryable et fournisseurs LINQ personnalisés.

J'utilise LINQ depuis un moment et je suis complètement à l'aise dans le monde IEnumerable et je peux résoudre la plupart des problèmes avec LINQ.

Mais lorsque j'ai commencé à examiner IQueryable, ainsi qu'à Expressions et aux fournisseurs linq personnalisés, j'ai eu le vertige. Examinez le fonctionnement de LINQ to SQL si vous voulez voir une logique assez complexe.

J'ai hâte de comprendre cet aspect de LINQ ...

6
Schneider

Je ne sais pas si cela peut être qualifié de mal compris - mais pour moi, tout simplement inconnu.

J'ai été ravi d'apprendre à propos de DataLoadOptions et à savoir comment contrôler les tables jointes lors de l'exécution d'une requête.

Voir ici pour plus d’informations: MSDN: DataLoadOptions

6
Martin

Comme la plupart des gens l'ont dit, je pense que la partie la plus mal comprise consiste à supposer que LINQ ne fait que remplacer T-SQL. Mon manager qui se considère en tant que gourou de TSQL ne nous laisserait pas utiliser LINQ dans notre projet et déteste même MS pour avoir publié une telle chose !!!

6
HashName

Je ne pense pas que tout le monde comprenne à quel point il est facile d'imbriquer une boucle.

Par exemple:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem
5
Rob Packwood

Que représente var quand une requête est exécutée?

Est-ce iQueryable, iSingleResult, iMultipleResult ou change-t-il en fonction de l'implémentation? Il y a des spéculations sur l'utilisation (ce qui semble être) du typage dynamique par rapport au typage statique standard en C #.

5
user31939

group by me fait encore tourner la tête.

Toute confusion à propos de exécution différée devrait pouvoir être résolue en parcourant un simple code basé sur LINQ et en jouant dans la fenêtre de surveillance.

4
Richard Everett

Requêtes compilées

Le fait que vous ne puissiez pas chaîner IQueryable car il s'agit d'appels de méthode (while toujours rien d'autre que du SQL traduisible!) Et qu'il est presque impossible de contourner ce problème est ahurissant et crée une énorme violation de DRY. J'ai besoin de mon IQueryable pour les tâches ad-hoc dans lesquelles je n'ai pas de requêtes compilées (je n'ai que des requêtes compilées pour les scénarios lourds), mais dans les requêtes compilées, je ne peux pas les utiliser, mais je dois écrire régulièrement requête à nouveau la syntaxe. Maintenant, je fais les mêmes sous-requêtes à 2 endroits, vous devez vous rappeler de mettre à jour les deux si quelque chose change, et ainsi de suite. Un cauchemar.

4
Alex

Je pense que la première idée fausse à propos de LINQ to SQL est que vous DEVEZ TOUJOURS CONNAÎTRE SQL afin de l'utiliser efficacement.

Une autre chose mal comprise à propos de Linq to Sql est que vous devez toujours réduire la sécurité de votre base de données à un point d’absurdité pour que cela fonctionne.

Un troisième point est que l'utilisation de Linq to Sql avec les classes dynamiques (ce qui signifie que la définition de classe est créée à l'exécution) provoque une énorme quantité de compilation juste à temps. Ce qui peut tuer absolument les performances.

4
NotMe

Chargement paresseux.

2
Ryan Eastabrook

Transactions (sans utiliser TransactionScope)

2
Naeem Sarfraz

Comme la plupart des gens l'ont dit, je pense que la partie la plus mal comprise consiste à supposer que LINQ ne fait que remplacer T-SQL. Mon manager qui se considère comme un gourou de TSQL ne nous laissera pas utiliser LINQ dans notre projet et déteste même MS pour avoir publié une telle chose !!!

2
stackuser1

Comme mentionné, chargement paresseux et exécution différée

Comment LINQ to Objects et LINQ to XML (IEnumerable) sont différents de LINQ to SQL (IQueryable)

COMMENT pour construire une couche d'accès aux données, une couche métier et une couche présentation avec LINQ dans toutes les couches ... et un bon exemple.

2
Ash Machine

Syntaxe de compréhension 'magique'. Comment la syntaxe de compréhension est-elle traduite en appels de méthodes et quels appels de méthodes sont choisis.

Comment, par exemple:

from a in b
from c in d
where a > c
select new { a, c }

se traduit en appels de méthode.

1
Pop Catalin

J'ai eu du mal à trouver des informations claires sur les types anonymes, notamment en ce qui concerne les performances dans les applications Web. De plus, je proposerais des exemples d’expressions Lamda de meilleure qualité et plus pratiques et une section "Comment faire" dans les rubriques relatives aux interrogations et aux performances.

J'espère que ma brève liste pourra vous aider!

1
GibboK

Expliquez pourquoi Linq ne gère pas la jointure externe gauche aussi simplement que dans la syntaxe SQL. Voir ces articles: Implémentation d'une jointure gauche avec LINQ , Comment: effectuer des jointures externes gauches (Guide de programmation C #) Je suis tellement déçu quand je suis tombé sur cet obstacle le respect de la langue a disparu et j'ai décidé que c'était simplement quelque chose qui disparaîtrait rapidement. Aucune personne sérieuse ne voudrait travailler avec une syntaxe qui manque de ces primitives éprouvées sur le champ de bataille. Si vous pouviez expliquer pourquoi ces opérations ne sont pas prises en charge. Je deviendrais une personne meilleure et plus ouverte d'esprit.

1

Je pense que vous devriez accorder plus d’attention aux fonctionnalités les plus couramment utilisées de LINQ - les expressions lambda et les types anonymes, plutôt que de perdre du temps sur des éléments "difficiles à comprendre" qui sont rarement utilisés dans les programmes du monde réel.

1
user21582

Ce n'est bien sûr pas "le plus difficile" mais juste quelque chose à ajouter à la liste:

ThenBy() extension method

Sans regarder sa mise en œuvre, je suis d'abord perplexe quant à son fonctionnement. Tout le monde comprend très bien comment les champs de tri séparés par des virgules fonctionnent en SQL - mais à première vue, je suis sceptique sur le fait que ThenBy fasse ce que je veux vraiment. Comment peut-il "savoir" ce qu'était le champ de tri précédent - il semble que cela devrait l'être.

Je pars à la recherche maintenant ...

1
Simon_Weaver

Je trouve que "Créer un arbre d'expression" est difficile. Il y a beaucoup de choses qui me dérangent avec ce que vous pouvez faire avec LINQ, LINQ to SQL et ADO.Net.

1
iTSrAVIE

Pour LINQ2SQL: Comprenez une partie du code SQL généré et écrivez des requêtes LINQ qui se traduisent par un code SQL correct (rapide). Cela fait partie de la problématique plus générale de savoir comment équilibrer la nature déclarative des requêtes LINQ avec le réalisme dont elles ont besoin pour s'exécuter rapidement dans un environnement connu (SQL Server).

Vous pouvez obtenir une requête générée par SQL complètement différente en modifiant une toute petite chose dans le code LINQ. Peut être particulièrement dangereux si vous créez un arbre d’expression basé sur des instructions conditionnelles (c’est-à-dire en ajoutant des critères de filtrage facultatifs).

1
Simon_Weaver

Comment LINQ to SQL le traduit!

Supposons que nous ayons une table avec 3 champs. A, B et C (Ce sont des entiers et le nom de la table est "Table1").
Je le montre comme ceci:
[A, B, C]

Maintenant, nous voulons obtenir un résultat tel que celui-ci:
[X = A, Y = B + C]

Et nous avons un tel cours:

public class Temp
{
   public Temp(int x, int y)
   {
      this.X = x;
      this.Y = y;
   }

   public int X { get; private set; }
   public int Y { get; private set; }
}

Ensuite, nous l'utilisons comme ceci:

using (MyDataContext db = new MyDataContext())
{
   var result = db.Table1.Select(row => 
                   new Temp(row.A, row.B + row.C)).ToList();
}

La requête SQL générée est:

SELECT [t0].[A] AS [x], [t0].[B] + [t0].[C] AS [y]
FROM [Table1] AS [t0]

Il traduit le .ctor du temp. Il sait que je veux que "row.B + row.C" (encore plus ...) mette le paramètre "y" de mon constructeur de classe!

Ces traductions sont très intéressantes pour moi. J'aime ça et je pense qu'écrire de tels traducteurs (LINQ to Something) est un peu difficile!

Bien sûr! C'est une mauvaise nouvelle: LINQ to Entities (4.0) ne prend pas en charge les constructeurs avec paramètres. (Pourquoi pas?)

1
Amir Karimi

Qui est plus rapide, en ligne Linq-to-Sql ou Linq-to-Sql en utilisant Tsql Sprocs

... et existe-t-il des cas où il est préférable d'utiliser des requêtes côté serveur (Sproc) ou côté client (Linq en ligne).

1
user31939

Je trouve un peu décevant que la syntaxe d'expression de requête ne prenne en charge qu'un sous-ensemble de la fonctionnalité LINQ. Vous ne pouvez donc pas éviter de chaîner les méthodes d'extension de temps en temps. Par exemple. la méthode Distinct ne peut pas être appelée à l'aide de la syntaxe d'expression de requête. Pour utiliser la méthode Distinct, vous devez appeler la méthode d'extension. D'autre part, la syntaxe de l'expression de requête est très pratique dans de nombreux cas, vous ne devez donc pas l'ignorer.

Une conférence sur LINQ pourrait inclure des instructions pratiques pour savoir quand préférer une syntaxe à une autre et comment les mélanger.

1
Brian Rasmussen

Le fait que vous ne puissiez pas chaîner IQueryable parce que ce sont des appels de méthode (même si rien n'est autre que du SQL traduisible!) Et qu'il est presque impossible de le contourner est ahurissant et crée une énorme violation de DRY. J'ai besoin de mon IQueryable pour les tâches ad-hoc dans lesquelles je n'ai pas de requêtes compilées (je n'ai que des requêtes compilées pour les scénarios lourds), mais dans les requêtes compilées, je ne peux pas les utiliser et je dois à nouveau écrire la syntaxe de requête régulière. Maintenant, je fais les mêmes sous-requêtes à 2 endroits, vous devez vous rappeler de mettre à jour les deux si quelque chose change, et ainsi de suite. Un cauchemar.

0
user305950