web-dev-qa-db-fra.com

Linq - Regroupement par date et sélection du nombre

Je travaille actuellement sur un problème où je voudrais exécuter une requête qui regroupe les résultats par date sélectionnée.

Pour cet exemple, imaginez un modèle simple comme ceci:

public class User
{
      public DateTime LastLogIn {get; set;}
      public string Name {get; set;}
}

La solution que je recherche est d'obtenir un nombre d'utilisateurs connectés par date. Dans la base de données, le DateTime sont stockés avec des composants de date et d'heure, mais pour cette requête, je ne me soucie vraiment que de la date.

Ce que j'ai actuellement, c'est ceci:

    context.Users
            .Where((x.LastLogIn  >= lastWeek)    
                && (x.LastLogIn <= DateTime.Now))
            .GroupBy(x => EntityFunctions.TruncateTime(x.LastLogIn))
            .Select(x => new
            {
                Value = x.Count(),
                Day = (DateTime)EntityFunctions.TruncateTime(x.Key)
            }).ToList();

Ce qui précède renvoie cependant une liste vide.

L'objectif final est d'avoir une liste d'objets, qui contient une valeur (le nombre d'utilisateurs connectés un jour) et un jour (le jour en question)

Des pensées?

En changeant la requête en:

    context.Users
            .Where((x.LastLogIn  >= lastWeek)    
                && (x.LastLogIn <= DateTime.Now))
            .GroupBy(x => EntityFunctions.TruncateTime(x.LastLogIn))
            .Select(x => new
            {
                Value = x.Count(),
                Day = (DateTime)x.Key
            }).ToList();

il renvoie désormais une liste avec un seul élément, la valeur étant le nombre total d'utilisateurs qui correspondent à la clause where et le jour étant le tout premier jour. Il n'a toujours pas semblé pouvoir se regrouper au fil des jours

REMARQUE: s'avère que le code ci-dessus est juste, je faisais juste autre chose de mal.

Sql qu'il génère est (notez qu'il peut y avoir de très légères erreurs syntaxiques ici avec moi l'ajustant pour l'exemple):

SELECT 
1 AS [C1], 
[GroupBy1].[A1] AS [C2], 
 CAST( [GroupBy1].[K1] AS datetime2) AS [C3]
FROM ( SELECT 
        [Filter1].[K1] AS [K1], 
        COUNT([Filter1].[A1]) AS [A1]
        FROM ( SELECT 
                 convert (datetime2, convert(varchar(255), [Extent1].[LastLogIn], 102) ,  102) AS [K1], 
                1 AS [A1]
                FROM [dbo].[Users] AS [Extent1]
                WHERE (([Extent1].[LastLogIn] >= @p__linq__1) AND ([Extent1].[LastLogIn] <= @p__linq__2)
        )  AS [Filter1]
       GROUP BY [K1]
)  AS [GroupBy1] 
25
Thewads

Vous n'avez pas besoin du deuxième TruncateTime dedans:

context.Users
    .Where((x.LastLogIn  >= lastWeek) && (x.LastLogIn <= DateTime.Now))
    .GroupBy(x => DbFunctions.TruncateTime(x.LastLogIn))
    .Select(x => new
    {
        Value = x.Count(),
        // Replace the commented line
        //Day = (DateTime)DbFunctions.TruncateTime(x.Key)
        // ...with this line
        Day = (DateTime)x.Key
    }).ToList();

GroupBy a déjà tronqué l'heure à partir de DateTime, vous n'avez donc pas besoin de l'appeler à nouveau.

Utiliser DbFunctions.TruncateTime vous devrez référencer l'Assemblée System.Data.Entity et inclure using System.Data.Entity;

Remarque: Modifié pour corriger la dépréciation de EntityFunctions.

26
dasblinkenlight

Essaye ça:

 .GroupBy(x => new {Year = x.LastLogIn.Year, Month = x.LastLogIn.Month, Day = x.LastLogIn.Day)
                .Select(x => new
                {
                    Value = x.Count(),
                    Year = x.Key.Year,
                    Month = x.Key.Month,
                    Day = x.Key.Day
                })
3
AD.Net

Vous pouvez le faire facilement:

yourDateList.GroupBy(i => i.ToString("yyyyMMdd"))
             .Select(i => new
             {
                 Date = DateTime.ParseExact(i.Key, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None),
                 Count = i.Count()
             });
2
SeyedPooya Soofbaf

Vous pouvez également le faire sur une seule ligne.

var b = (from a in ctx.Candidates select a)
            .GroupBy(x => x.CreatedTimestamp.Date).Select(g => new { Date=(g.Key).ToShortDateString(), Count = g.Count() });
1
Yahiya Iqbal