Share via


GQ08 VI: l'équivalent de 'in' avec Linq to Sql

Linq to Sql est capable de générer le 'in' Sql. Cela se traduit en Linq par l'usage de la méthode .Contains(). L'exemple ci-dessous compile mais pourtant plante à l'exécution.

Pourquoi donc ?

 var db = new NorthwindDataContext();
var cq =
    CompiledQuery.Compile((NorthwindDataContext ctx, string[] cities) =>
        from c in ctx.Customers
        where cities.Contains(c.City)
        select c);
var list = cq(db, new string[] {"Paris", "London"}).ToList();

Comments

  • Anonymous
    August 19, 2008
    PingBack from http://informationsfunnywallpaper.cn/?p=1219

  • Anonymous
    August 19, 2008
    The comment has been removed

  • Anonymous
    August 19, 2008
    Il me semble qu'une requête qui a des parametres de type liste ne compile pas car l'opération de compilation dépend du nombre d'éléments dans la ou les listes passées en parametre. En version non précompilée la requête fonctionne d'ailleurs. En revanche je ne connais de solution simple pour contourner le problème, j'attends avec impatience ta solution !

  • Anonymous
    August 19, 2008
    The comment has been removed

  • Anonymous
    August 19, 2008
    Deux bonnes réponses. En effet, le but des CompiledQueries est de conserver le sql généré lors du premier appel afin de ne pas faire la conversion 'expression' vers 'sql' à chaque appel. C'est un moyen très efficace de gagner en performance avec Linq to Sql, surtout sur les requêtes complexes. Ce mécanisme à cependant une limitation, le 'in' sql ne peut pas être supporté. En effet, le nombre de paramètres fera varier le sql avec un 'in (..,..)' ayant plusieurs valeurs. Ce sql ne peut donc pas être factorisé. Cette limitation n'est pas propre à Linq, c'est évidemment la même chose avec des requêtes paramétrées ou même des procédures stockées qui ne peuvent pas non plus factoriser un 'in' et ses paramètres. Olivier désolé mais pas de solution :p La seule chose que l'on peut faire si le nombre de paramètres de la liste est fixe est: var cq2 =    CompiledQuery.Compile((NorthwindDataContext ctx, string city1, string city2) =>        from c in ctx.Customers        where new string[] { city1, city2}.Contains(c.City)        select c); var list = cq2(db, "Paris", "London").ToList(); ...comme on pourrait le faire avec une procédure stockée. Mention spéciale pour Matthieu qui a posté qu'un seul commentaire de taille raisonnable. :p

  • Anonymous
    August 19, 2008
    The comment has been removed

  • Anonymous
    August 20, 2008
    The comment has been removed

  • Anonymous
    August 20, 2008
    Désolé à tous, j'avais activé la modération :). Elle n'y est plus désormais. Oui Olivier, la solution la plus "base de données" serait en effet de remplir une table temporaire avec une sorte d'ID de transaction et de s'en servir pour injecter les valeurs du 'in'. S'il n'y a pas beaucoup de données c'est en effet un effort pour pas grand chose. S'il y en a beaucoup ce n'est pas choquant, les moteurs de bases de données utilisent eux-mêmes en interne une multitude de tables temporaires ne serait-ce que pour les transactions. Simon, en effet il est fort possible que ton cas soit identique et fasse échouer une compiled query. Il faudrait tester. Qui a Sql2000 :p ?