简体   繁体   English

使用 LINQ to Entities 的时间跨度总和

[英]Sum of Timespans using LINQ to Entities

I have a group by LINQ call and then sum the PossessionTime.Tick values as a new Timespan.我有一个通过 LINQ 调用的组,然后将 PossessionTime.Tick 值相加为一个新的时间跨度。 This worked fine before, but now I need to keep the collection as an IQueryable instead of a List.这以前工作得很好,但现在我需要将集合保留为 IQueryable 而不是列表。

PossessionTime = new TimeSpan(x.Sum(p => p.PossessionTime.Ticks))

With this change I now get the following error:通过此更改,我现在收到以下错误:

Only parameterless constructors and initializers are supported in LINQ to Entities. LINQ to Entities 仅支持无参数构造函数和初始值设定项。

I've looked into using DbFunctions but it doesn't have anything that can help I dont think.我已经研究过使用DbFunctions但它没有任何可以帮助我认为的东西。

Is my only option to move the list into memory and sum the time there?我唯一的选择是将列表移动到内存中并总结那里的时间吗?

The IQueryable is as follows: IQueryable 如下:

return stats.GroupBy(x => x.Id).OrderByDescending(x => x.Sum(a => a.Kills))
            .Select(x => new WeaponItem
            {         
                PossessionTime = new TimeSpan(x.Sum(p => p.PossessionTime.Ticks))
            });

I need to keep it as an IQueryable as Im using it in pagination.我需要将它保留为 IQueryable,因为我在分页中使用它。

I don't think you'll be able to do this very easily with Linq-to-SQL/EF using straight linq becuase of PossionTime.Ticks .我认为您无法使用 Linq-to-SQL/EF 轻松完成此操作,因为PossionTime.Ticks使用直接 linq。 C# DateTime operations are very limited when translating into sql operations. C# DateTime 操作在转换为 sql 操作时非常有限。

If your only requirement is to support pagination, you could make it easy on yourself by doing your WeaponItem projection after your pagination operation and have pulled you the page into memory:如果您唯一的要求是支持分页,您可以通过在分页操作后进行WeaponItem投影并将页面拉入内存来WeaponItem自己:

return stats
   .GroupBy(x => x.Id)
   .OrderByDescending(x => x.Sum(a => a.Kills))
   // paginatation
   .Skip(pageNumber * pageSize)
   .Take(pageSize)
   // pull paged result set into memory to make life easy
   .ToList()
   // transform into WeaponItem
   .Select(x => new WeaponItem
   {         
        PossessionTime = new TimeSpan(x.Sum(p => p.PossessionTime.Ticks))
   });

Alternatively, you could change your WeaponItem class to store PossesionTimeTicks and then offer PossesionTime as a computed property.或者,您可以更改您的WeaponItem类以存储PossesionTimeTicks ,然后将PossesionTime作为计算属性提供。 That might get around the restricton:这可能会绕过限制:

public class WeaponItem
{
    public long PosseionTimeTicks {get;set;}
    public TimeSpan PossesionTime {get{ return new TimeSpan(PosseionTimeticks); }
}

Then I think you should be able to keep your query as an IQueryable:然后我认为您应该能够将您的查询保留为 IQueryable:

return stats
    .GroupBy(x => x.Id)
    .OrderByDescending(x => x.Sum(a => a.Kills))
    .Select(x => new WeaponItem
    {         
        PossessionTimeTicks = x.Sum(p => p.PossessionTime.Ticks)
    });

You can create a TimeSpan from HMS using DBFunctions.CreateTime , so you could do math to convert:您可以使用DBFunctions.CreateTime从 HMS 创建一个TimeSpan ,因此您可以进行数学运算来转换:

return stats.GroupBy(x => x.Id).OrderByDescending(x => x.Sum(a => a.Kills))
            .Select(x => new WeaponItem
            {         
                PossessionTime = DBFunctions.CreateTime(0, 0, x.Sum(p => DBFunctions.DiffSeconds(p.PossessionTime, TimeSpan.Zero)))
            });

Note: I am assuming CreateTime will accept a seconds argument >= 60 seconds, if not, you would need to convert the sum to hours, minutes and seconds.注意:我假设CreateTime将接受一个 >= 60 秒的秒参数,否则,您需要将总和转换为小时、分钟和秒。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM