Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

Petit quizz LINQ To SQL

Le code suivant :

using (var context = new DataClasses1DataContext())

{

    int[] keyValues = { 1, 2, 3 };

    var q = from p in context.Products

            where keyValues.Contains(p.ProductID)

            select p;

    var r = new

    {

        Count = q.Count(),

        CountCategory = (from p in q

                        select p.CategoryID).Distinct().Count(),

        AverageUnitPrice = (from p in q

                            select p.UnitPrice).Average()

    };

    // Do something with r

}

 

a le défaut majeur de générer 3 requêtes SQL :

 

SELECT COUNT(*) AS [value]
FROM [dbo].[Products] AS [t0]
WHERE [t0].[ProductID] IN (@p0, @p1, @p2)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [3]

 

SELECT COUNT(*) AS [value]
FROM (
    SELECT DISTINCT [t0].[CategoryID]
    FROM [dbo].[Products] AS [t0]
    WHERE [t0].[ProductID] IN (@p0, @p1, @p2)
    ) AS [t1]
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [3]

 

SELECT AVG([t0].[UnitPrice]) AS [value]
FROM [dbo].[Products] AS [t0]
WHERE [t0].[ProductID] IN (@p0, @p1, @p2)
-- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
-- @p1: Input Int (Size = 0; Prec = 0; Scale = 0) [2]
-- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [3]


 

Comment faire en sorte de n'exécuter qu'une seule requête SQL ?

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié lundi 10 mars 2008 08:13 par Matthieu MEZIL

Classé sous : , , , ,

Commentaires

# re: Petit quizz LINQ To SQL @ lundi 10 mars 2008 19:19

J'avoue que je ne vois pas la solution.

Enfin j'en vois une mauvaise qui serait de forcer l'execution de q avant d'appeller les Count et Average:

var q = (from p in context.Products

           where keyValues.Contains(p.ProductID)

           select p).ToArray();

par exemple.

Apres évidement, les Count et Average sont executes par Linq to Object et ne génèrent donc plus de requetes SQL. Mais c'est une mauvaise solution: ca serait bête d'être obligé de récupérer 1 million de lignes pour juste faire un count et average, alors que ca aurait pu etre fait coté SQL Server: gachis de mémoire, de bande passante et de CPU.

Je suis intéressé par la solution en tout cas :)

RaptorXP

# re: Petit quizz LINQ To SQL @ lundi 10 mars 2008 22:00

Effectivement ce n'est pas la meilleure solution car cela implique de récupérer l'ensemble des enregistrements de la base vers la mémoire.

Personne d'autre n'a d'idée ? ;-)

Matthieu MEZIL

# re: Petit quizz LINQ To SQL @ lundi 10 mars 2008 22:55

Bon alors, c'est quoi la solution ? :)

Thomas LEBRUN

# re: Petit quizz LINQ To SQL @ lundi 10 mars 2008 23:52

int[] keyValues = { 1, 2, 3 };

var q = from gp in

           (from p in ctx.Products

            where keyValues.Contains(p.ProductID)

            group p by p.CategoryID into groupOfProds

            select new

            {

                ProductCount = groupOfProds.Count(),

                TotalUnitPrice = groupOfProds.Sum(prod => prod.UnitPrice)

            })

       group gp by 0 into gp2

       select new

       {

           CategoryCount = gp2.Count(),

           Count = gp2.Sum(gp => gp.ProductCount),

           AverageUnitPrice = gp2.Sum(gp => gp.TotalUnitPrice) / gp2.Sum(gp => gp.ProductCount)

       };

Console.WriteLine(q.FirstOrDefault());

Enjoy!

Le soucis c'est les deux niveaux d'agrégation dans la même requête, et surtout, l'aggrégation sur les catégories (qui doit retourner qu'une seule ligne). La grosse feinte dans ma requete, c'est le group gp by 0 into gp2 qui me permet d'aggréger les données de toutes les catégories dans une seule ligne ^^

simon ferquel

# re: Petit quizz LINQ To SQL @ mardi 11 mars 2008 13:01

En SQL c'est plus simple :

SELECT COUNT(*) AS [value1], AVG([t0].[UnitPrice]) AS [value2], COUNT(DISTINCT [CategoryID])  AS [value3]

FROM [dbo].[Products] AS [t0]

WHERE [t0].[ProductID] IN (@p0, @p1, @p2)

!!!

christian

# re: Petit quizz LINQ To SQL @ mardi 11 mars 2008 13:14

Ok, ca a l'air quand meme un peu trop complique, personellement je préfererais encore faire 3 requetes et avoir un code plus maintenable. Mais c'est bien de savoir que c'est possible.

A mon avis, il faut éviter les chargements différées surtout dans les boucles, mais quand le nombre de requetes supplémentaires est constant (ici 3 au lieu d'une), je ne pense pas que les performances ne soit vraiment impactées.

RaptorXP

# re: Petit quizz LINQ To SQL @ mardi 11 mars 2008 17:36

Pas mal Simon. Effectivement, l'idée est de faire un group by sur une constante. Moi j'avais pensé à cette requête :

var q2 = (from p in context.Products

         where keyValues.Contains(p.ProductID)

         group p by 0 into g

         select new { Count = g.Count(), CountCategory = g.Select(p => p.CategoryID).Distinct().Count(), AverageUnitPrice = g.Average(p => p.UnitPrice) }).First();

Cependant la requête générée :

SELECT TOP (1) [t5].[value] AS [Count], [t5].[value2] AS [CountCategory], [t5].[value22] AS [AverageUnitPrice]

FROM (

   SELECT [t2].[value], (

       SELECT COUNT(*)

       FROM (

           SELECT DISTINCT [t3].[CategoryID]

           FROM [dbo].[Products] AS [t3]

           WHERE ([t2].[value3] = @p4) AND ([t3].[ProductID] IN (@p1, @p2, @p3))

           ) AS [t4]

       ) AS [value2], [t2].[value2] AS [value22]

   FROM (

       SELECT COUNT(*) AS [value], AVG([t1].[UnitPrice]) AS [value2], [t1].[value] AS [value3]

       FROM (

           SELECT @p0 AS [value], [t0].[ProductID], [t0].[UnitPrice]

           FROM [dbo].[Products] AS [t0]

           ) AS [t1]

       WHERE [t1].[ProductID] IN (@p1, @p2, @p3)

       GROUP BY [t1].[value]

       ) AS [t2]

   ) AS [t5]

n'est pas optimale. Dans ce cas là, il peut être intéressant de se créer une fonction sql avec la requête triviale donnée par Christian et de l'importer dans notre DataContext.

Matthieu MEZIL

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Les actualités de la semaine sur c2i.fr (14 mai - 20 mai) par Richard Clark le il y a 5 heures et 5 minutes

- Reactive Extensions : Consommer des services avec Rx Partie 3, les pièges à éviter par Léonard Labat le il y a 14 heures et 10 minutes

- SharePoint Blog Site, problème d’archives par Le Blog (Vert) d'Arnaud JUND le 05-20-2012, 13:09

- Soirée ALT.NET Mai - 3 présentations par #Rui le 05-18-2012, 11:59

- [ #SharePoint 2010][ #SQLServer 2012] AlwaysOn pour SharePoint (2/4) : Configuration (2e partie)… par Le blog de Patrick [MVP SharePoint] le 05-18-2012, 11:31

- Team Foundation Server 11: tous les trésors cachés du site d’équipe par Philess le 05-16-2012, 19:01

- [PowerShell 3] Télécharger et installer la documentation en ligne par Blog de SPBrouillet (Pierrick BROUILLET) le 05-16-2012, 17:36

- [#SharePoint 2010][#SQLServer 2012] AlwaysOn pour SharePoint (1/4) : Configuration (1ère partie)… par Le blog de Patrick [MVP SharePoint] le 05-16-2012, 12:10

- Job Day @MIC Brussels - .Net Developers on Mobile applications par Le Blog (Vert) d'Arnaud JUND le 05-15-2012, 20:26

- [SharePoint 2010] – SharePoint 2010, Windows (Server) 8 et des erreurs IIS sont dans une VM… par Blog de SPBrouillet (Pierrick BROUILLET) le 05-14-2012, 12:10