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

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01