EntityFramework GroupBy与DBFunctions或替代

时间:2016-04-24 13:49:25

标签: c# multithreading entity-framework

我有100行不同日期的数据。我希望将结果按每30分钟相同的日期进行分组。

相反:
结果1 2016-02-02 13:00:24
结果1,2016-02-02 13:01:24
结果1,2016-02-02 13:02:24
结果1,2016-02-02 13:33:24

需要:

结果1,2016-02-02 13:00:24
结果1,2016-02-02 13:33:24

原始查询:

C:\Backup\

我尝试了什么:

    return await loc.Where(p => p.ReadTime >= df && p.ReadTime <= dt)
        .OrderBy(p => p.ReadTime)
        .ProjectTo<LocationModel>().ToListAsync();

堆栈跟踪错误:

  

.ThrowForNonSuccess(任务任务)\ r \ n at   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification   (任务任务)\ r \ n at   System.Runtime.CompilerServices.TaskAwaiter 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(); 1   结果)\ r \ n at   System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke(个)\ r \ n   在System .Threading.Tasks.Task.Execute()\ r \ n ---堆栈跟踪结束   从之前的位置抛出异常--- \ r \ n at   System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务   任务)\ r \ n at   System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务   任务)\ r \ n at   System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition。      

    

d__c.MoveNext()&#34;,&#34; innerException&#34;:{&#34; message&#34;:&#34;发生错误。&#34;,&#34; exceptionMessage&#34;:&#34;等待操作定时     出&#34;&#34; exceptionType&#34;:&#34; System.ComponentModel.Win32Exception&#34;&#34;堆栈跟踪&#34;:空}}}

  

1 个答案:

答案 0 :(得分:1)

除了将所有数据加载到内存中并根据需要手动格式化之外,我可以想到用单个查询执行此操作的唯一可行方法是将行放入预定义日期“buckets”和从每个桶中选择一行。

桶的最合乎逻辑的选择是在你寻找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的DateTime位。