我正在尝试使用 EF Core 3 查询数据库,按日期和时间对 DateTime 字段进行分组,并在选择时将小时部分添加到日期。到目前为止,我所有的 Linqs 都失败了。
失败案例 1。使用"添加小时数"将小时数添加到"日期"。
Logs.GroupBy(g => new
{
g.DateStamp.Date,
g.DateStamp.Hour,
g.Result
}).Select(s => new
{
Date = s.Key.Date.AddHours(s.Key.Hour),
s.Key.Result,
Conversions = s.Count(),
Cost = s.Sum(sum => sum.ConversionCost)
}).OrderBy(o => o.Date)
错误:
日期函数不支持日期部分小时 日期为数据添加 键入日期。
不确定问题出在哪里,Linq 到实体提供程序不支持 AddHours 或 s.Key.Date 字段不能再包含小时数,因为它变成了仅日期字段。
失败案例 2。创建新的日期时间对象并传递变量。
Logs.GroupBy(g => new
{
g.DateStamp.Date,
g.DateStamp.Hour,
g.Result
}).Select(s => new
{
Date =new DateTime(s.Key.Date.Year, s.Key.Date.Month, s.Key.Date.Day, s.Key.Hour, 0, 0),
s.Key.Result,
Conversions = s.Count(),
Cost = s.Sum(sum => sum.ConversionCost)
}).OrderBy(o => o.Date)
错误:
无效操作异常:LINQ 表达式 'OrderBy<<>f__AnonymousType1, DateTime>( 来源: Selectf__AnonymousType0, 日志>, <>f__AnonymousType1>( 来源: GroupByf__AnonymousType0, 日志>( 来源: 数据库集, 键选择器: (l( => new { Date = l.DateStamp.Date, 小时 = l.日期戳.小时, 结果 = l.结果 }, 元素选择器: (l( => l(, 选择器: (e( => 新 { 日期 = 新的日期时间( e.key.date.year, e.Key.Date.Month, e.Key.Date.Day, e.Key.Hour, 0, 0 ), 结果 = e.key.result, 转化次数 = 计数(e(, 成本 = 总和( 资料来源:E, 选择器:(总和(=>总和。转换成本( }), 键选择器: (e0( => e0.日期("无法翻译。以可翻译的形式重写查询,或切换到 通过插入对任一 AsEnumerable((, AsAsyncEnumerable((, ToList(( 或 ToListAsync((。看 https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。
OrderBy(o => o.Date)
停止工作并给出异常,为什么?我也不知道。
因此,最后一个问题是,如何使用EF Core按日期+小时对SQL数据库中的DateTime字段进行分组,并将其移动到"选择"到一个字段中,并在最后按新日期字段执行OrderBy。
我可以对失败案例 1 发表评论,因为我也遇到了同样的问题。
x.Date
将转换为 SQL 作为CONVERT(date, x)
x.AddHours(y)
将转换为 SQL 作为DATEADD(hour, x, y)
- 我们两者都有,所以它
DATEADD(hour, CONVERT(date, x), y)
,这是不可能的,因为您无法向date
类型的数据添加小时数,因此会出现错误消息。
在sql级别,它通常通过向datetime2
添加额外的强制转换来修复,就像
CAST(CONVERT(date, x) AS datetime2)
因此,您再次在datetime2
级别上处理,并能够为结果值添加小时数。
话虽如此,我不知道如何强制 EF 生成额外的强制转换((DateTime)
或Convert.ToDateTime
都没有帮助(,所以这是我想出的解决方法(不能说它是否会因溢出而失败一次(
x.AddMilliseconds(-EF.Functions.DateDiffMillisecond(TimeSpan.Zero, x.TimeOfDay))
.AddHours(y)
使用 EF Core 3.1.12 对其进行了测试,它按预期对我有用。这是输出
(DATEADD(
hour,
CAST(y AS int),
DATEADD(
millisecond,
CAST(
CAST(
-DATEDIFF(MILLISECOND, '00:00:00', CAST(x AS time)) AS float) AS int
),
x
)
)
会猜测情况 2 失败,因为 EF 无法翻译new DateTime
表达式,但这只是错误是神秘的。
我在使用 EFCore 6 时遇到了同样的问题,我在执行 Date.AddHours 时遇到错误,因为它看起来像是投射到日期而不是日期时间。为了让它工作,我必须投射到对象,然后投射到DATETIME,然后我才能添加我的小时数。
Logs.GroupBy(g => new
{
g.DateStamp.Date,
g.DateStamp.Hour,
g.Result
}).Select(s => new
{
Date = ((DateTime)(object)s.Key.Date).AddHours(s.Key.Hour),
s.Key.Result,
Conversions = s.Count(),
Cost = s.Sum(sum => sum.ConversionCost)
}).OrderBy(o => o.Date)