LINQ GroupBy DateTime进退两难

时间:2011-10-28 21:04:20

标签: linq ef-code-first

我有以下代码:

public IDictionary<string, int> GetCountByDate(DateTime fromDate, DateTime toDate)
{
    var result = Database.Set<User>().Where(x => x.CreatedAt >= fromDate && x.CreatedAt <= toDate).GroupBy(x => new { x.CreatedAt.Year, x.CreatedAt.Month, x.CreatedAt.Day }).Select(x => new { Date = x.Key, Count = x.Count() });

    return result.ToDictionary(x => new DateTime(x.Date.Year, x.Date.Month, x.Date.Day).ToShortDateString(), x => x.Count);
}

此代码运行良好,但问题是DateTime在数据库中存储为UTC。在我进行GroupBy操作的那一刻,我失去了Time部分。因此,如果我尝试使用以下内容将其转换回本地时间:

return result.ToDictionary(x => new DateTime(x.Date.Year, x.Date.Month, x.Date.Day).ToLocalTime().ToShortDateString(), x => x.Count);

这将基于不同的时间,因此不正确。该列必须保留DateTime。

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

听起来真正的挑战是你需要翻译两次。首先,采用当地的DateTime,您需要将该方法(您的问题只有在本地时才有意义)转换为UTC以进行查询。但是,在你对服务器进行分组之前,你需要将x.CreatedAt翻译成本地,换句话说。这很棘手,但如果您在System.Data.Objects.SqlClient中使用SqlFunctions库,则可以正常工作。这就是它的样子。凌乱,我不知道它有多高效,但它应该有用。

public IDictionary<string, int> GetCountByDate(DateTime fromDate, DateTime toDate) 
{ 
    DateTime utcFrom = fromDate.ToUniversalTime();
    DateTime utcTo = toDate.ToUniversalTime();
    int offset = (int)(fromDate - utcFrom).TotalHours;
    var result = Database.Set<User>().Where(x => x.CreatedAt >= utcFrom && x.CreatedAt <= utcTo)
        .GroupBy(x => new { 
            SqlFunctions.DateAdd("hh", offset, x.CreatedAt).Value.Year, 
            SqlFunctions.DateAdd("hh", offset, x.CreatedAt).Value.Month, 
            SqlFunctions.DateAdd("hh", offset, x.CreatedAt).Value.Day })
        .Select(x => new { Date = x.Key, Count = x.Count() });

    return result.ToDictionary(x => new DateTime(x.Date.Year, x.Date.Month, x.Date.Day).ToShortDateString(), x => x.Count); 
} 

此时,字典对象中的日期值已经是本地时间,因此无需将它们转换为演示文稿。