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]
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
.
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
})
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()
});
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() });