使用 LINQ to Entities 的时间跨度总和
Sum of Timespans using LINQ to Entities
我通过 LINQ 调用进行分组,然后将 PossessionTime.Tick 值相加作为新的时间跨度。这以前工作得很好,但现在我需要将集合保留为 IQueryable 而不是 List。
PossessionTime = new TimeSpan(x.Sum(p => p.PossessionTime.Ticks))
通过此更改,我现在收到以下错误:
Only parameterless constructors and initializers are supported in LINQ
to Entities.
我研究过使用 DbFunctions
,但我认为它没有任何可以帮助我的东西。
我唯一的选择是将列表移入内存并在内存中求和时间吗?
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))
});
我需要将它保留为 IQueryable,因为我在分页中使用它。
我不认为你能够通过 Linq-to-SQL/EF 使用直接的 linq 很容易地做到这一点,因为 PossionTime.Ticks
。 C# DateTime 操作在转换为 sql 操作时非常有限。
如果您的唯一要求是支持分页,您可以通过在分页操作后进行 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))
});
或者,您可以将 WeaponItem
class 更改为存储 PossesionTimeTicks
,然后提供 PossesionTime
作为计算 属性。这可能会绕过限制:
public class WeaponItem
{
public long PosseionTimeTicks {get;set;}
public TimeSpan PossesionTime {get{ return new TimeSpan(PosseionTimeticks); }
}
那么我认为您应该能够将查询保留为 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)
});
您可以使用 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)))
});
注意: 我假设 CreateTime
将接受秒参数 >= 60 秒,否则,您需要将总和转换为小时、分钟和秒。
我通过 LINQ 调用进行分组,然后将 PossessionTime.Tick 值相加作为新的时间跨度。这以前工作得很好,但现在我需要将集合保留为 IQueryable 而不是 List。
PossessionTime = new TimeSpan(x.Sum(p => p.PossessionTime.Ticks))
通过此更改,我现在收到以下错误:
Only parameterless constructors and initializers are supported in LINQ to Entities.
我研究过使用 DbFunctions
,但我认为它没有任何可以帮助我的东西。
我唯一的选择是将列表移入内存并在内存中求和时间吗?
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))
});
我需要将它保留为 IQueryable,因为我在分页中使用它。
我不认为你能够通过 Linq-to-SQL/EF 使用直接的 linq 很容易地做到这一点,因为 PossionTime.Ticks
。 C# DateTime 操作在转换为 sql 操作时非常有限。
如果您的唯一要求是支持分页,您可以通过在分页操作后进行 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))
});
或者,您可以将 WeaponItem
class 更改为存储 PossesionTimeTicks
,然后提供 PossesionTime
作为计算 属性。这可能会绕过限制:
public class WeaponItem
{
public long PosseionTimeTicks {get;set;}
public TimeSpan PossesionTime {get{ return new TimeSpan(PosseionTimeticks); }
}
那么我认为您应该能够将查询保留为 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)
});
您可以使用 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)))
});
注意: 我假设 CreateTime
将接受秒参数 >= 60 秒,否则,您需要将总和转换为小时、分钟和秒。