Linq - группировка по дате и выбор счетчика
В настоящее время я работаю над проблемой, когда я хотел бы запустить запрос, который группирует результаты по выбранной дате.
В этом примере представьте себе такую простую модель:
public class User
{
public DateTime LastLogIn {get; set;}
public string Name {get; set;}
}
Решение, которое я ищу, - это подсчет количества зарегистрированных пользователей по дате.
В базе данных DateTime хранятся с компонентами даты и времени, но для этого запроса я действительно забочусь только о дате.
В настоящее время у меня есть:
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();
Приведенное выше возвращает пустой список.
Конечная цель состоит в том, чтобы иметь список объектов, которые содержат значение (количество зарегистрированных пользователей в день) и день (день, о котором идет речь)
Любые мысли?
После изменения запроса на:
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();
теперь он возвращает список с одним элементом, а значение - это общее количество пользователей, которое соответствует предложению where, а день - самый первый день. Кажется, он все еще не мог группироваться по дням.
ПРИМЕЧАНИЕ: оказывается, что приведенный выше код прав, я просто делал что-то еще не так.
Sql, который он генерирует, (обратите внимание, что здесь могут быть очень незначительные синтаксические ошибки, когда я настраиваю его для примера):
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]
Ответы
Ответ 1
Вам не нужен второй TruncateTime
там:
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
уже GroupBy
время с DateTime
, поэтому вам не нужно вызывать его снова.
Чтобы использовать DbFunctions.TruncateTime
вам нужно сослаться на сборку System.Data.Entity
и включить using System.Data.Entity;
Примечание. Отредактировано для устранения устаревания EntityFunctions
.
Ответ 2
Попробуйте следующее:
.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
Вы можете сделать это легко:
yourDateList.GroupBy(i => i.ToString("yyyyMMdd"))
.Select(i => new
{
Date = DateTime.ParseExact(i.Key, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None),
Count = i.Count()
});
Ответ 4
Вы также можете сделать это в одной строке.
var b = (from a in ctx.Candidates select a)
.GroupBy(x => x.CreatedTimestamp.Date).Select(g => new { Date=(g.Key).ToShortDateString(), Count = g.Count() });