C# EntityFramework GroupBy与DBFunctions或alternative
我有100行不同日期的数据。我想按结果分组,每次间隔30分钟,日期相同 相反: 结果12016-02-02 13:00:24 结果12016-02-0213:01:24 结果12016-02-0213:02:24 结果12016-02-0213:33:24 需要: 结果12016-02-02 13:00:24 结果12016-02-0213:33:24 原始查询:C# EntityFramework GroupBy与DBFunctions或alternative,c#,multithreading,entity-framework,C#,Multithreading,Entity Framework,我有100行不同日期的数据。我想按结果分组,每次间隔30分钟,日期相同 相反: 结果12016-02-02 13:00:24 结果12016-02-0213:01:24 结果12016-02-0213:02:24 结果12016-02-0213:33:24 需要: 结果12016-02-02 13:00:24 结果12016-02-0213:33:24 原始查询: return await loc.Where(p => p.ReadTime >= df &&
return await loc.Where(p => p.ReadTime >= df && p.ReadTime <= dt)
.OrderBy(p => p.ReadTime)
.ProjectTo<LocationModel>().ToListAsync();
我尝试的是:
return await loc.Where(p => p.ReadTime >= df && p.ReadTime <= dt)
.GroupBy(p => DbFunctions.TruncateTime(p.ReadTime))
.Select(p => new LocationModel
{
Lng = p.FirstOrDefault().Lng,
Lat = p.FirstOrDefault().Lat
})
.ToListAsync();
堆栈跟踪错误:
.ThrowForNonSuccessTask任务\r\n位于
System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification
任务任务\r\n位于
System.Runtime.CompilerServices.TaskWaiter1.GetResult\r\n位于
System.Web.Http
.Dispatcher.HttpControllerDispatcher.d_u1.MoveNext,innerException:{message:An
发生错误。异常消息:超时已过期。异常消息
在完成操作之前经过的超时时间或
服务器不可用
正在响应,异常类型:System.Data.SqlClient.SqlException
,stackTrace:at
System.Data.SqlClient.SqlCommand.c.b_u167_0Task1
结果\r\n在
System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke\r\n
在System.Threading.Tasks.Task.Execute上\r\n--堆栈结束跟踪
从引发异常的上一个位置--\r\n
System.Runtime.CompilerServices.TaskWaiter.ThrowForNonSuccessTask
任务\r\n位于
System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotificationTask
任务\r\n位于
System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition。
d_uc.MoveNext,innerException:{消息:发生错误,。异常消息:等待操作超时
out,exceptionType:System.ComponentModel.Win32Exception,stackTrace:null}
除了将所有数据加载到内存中并根据需要手动对其进行格式化之外,我能想到的唯一可行的方法是使用单个查询将行放入预定义的日期桶中,并从每个桶中选择一行 桶的最合理选择是在一小时半,因为您需要30分钟的间隔,例如:
Result 1, 2016-02-02 13:00:24, 2016-02-02 13:00:00 (bucket 1)
Result 1, 2016-02-02 13:01:24, 2016-02-02 13:00:00 (bucket 1)
Result 1, 2016-02-02 13:02:24, 2016-02-02 13:00:00 (bucket 1)
Result 1, 2016-02-02 13:33:24, 2016-02-02 13:30:00 (bucket 2)
下一个要解决的问题是为每个铲斗选择要使用的行。您可以使用的一种方法是确定最接近桶最小值的日期并使用它:
from l in loc
join bucket in (
from l in loc
group l by new DateTime(l.ReadTime.Year, l.ReadTime.Month, l.ReadTime.Day, l.ReadTime.Hour, l.ReadTime.Minute < 30 ? 0 : 30, 0) into g
select g.Min(m => m.ReadTime)
) on l.ReadTime equals bucket
select new LocationModel
{
Lng = l.FirstOrDefault().Lng,
Lat = l.FirstOrDefault().Lat
}
但是,需要注意这种方法,因为如果存在具有相同日期/时间值的行,则可能会导致重复。如果实体/表使用标识列作为主键,并且以日期/时间顺序将行插入表中,则可以使用该键确定每个存储桶的行,因为该键有效地按升序排列:
from l in loc
join bucket in (
from l in loc
group l by new DateTime(l.ReadTime.Year, l.ReadTime.Month, l.ReadTime.Day, l.ReadTime.Hour, l.ReadTime.Minute < 30 ? 0 : 30, 0) into g
select g.Min(m => m.Id)
) on l.Id equals bucket
select new LocationModel
{
Lng = l.FirstOrDefault().Lng,
Lat = l.FirstOrDefault().Lat
}
这将确保没有重复项。否则,您要么需要在代码中过滤重复项,要么进一步扩展查询。我对你的特定领域了解不够,所以我将把这部分留给你来解决
我还应该指出,上面的查询是由Linq to SQL支持的,但是如果不支持某些东西,例如DbFunctions.CreateDateTime,您可能需要使用DbFunctions类作为带有EF的日期时间位。我认为这是不可能的。首先,你发布的测试数据总是有24秒;如果最后一行是Result 12016-02-02 13:33:25,会发生什么?您是否希望将其包括在内,因为它已不再是第一次会议后的30分钟了?也许可以构造一些SQL,但我不知道您有什么RDBMS。对不起,我应该说,我认为不检索所有行并在代码中迭代它们是不可能的。我想不出一个SQL语句可以做到这一点,如果不存在,EF也无法在上下文中创建查询时做到这一点。另外,您正在调用.Select在一个I分组上,而不是按列聚合或分组,因此我认为GroupBy语法不是您真正想要的。