DBContext 对象 LINQ Sum(time) 列到小时



这是一个 ASP.Net 核心Web API项目,使用EntityFrameWorkCore。 我需要将 TotalLoggedInTime(格式:139:05:40(转换为小时数,并对小时求和并将其分配给登录小时数,但它在该行上失败。 调用提供的第一行工作正常。

C# 代码:

internal void Hydrate(DbSet<MyObj> myObj)
{
string callsOffered = myObj.Sum(a => a.CallsPresented).ToString();
string logonHours = myObj.Sum(a => TimeSpan.Parse(a.TotalLoggedInTime).TotalHours).ToString();
}

SQL 表

SELECT total_logged_in_time FROM mytable
total_logged_in_time
139:05:40
157:22:46
157:26:51
148:17:42
157:23:14
138:04:28
175:27:41
162:35:44
163:13:13
144:36:12
9:01:56

错误

LINQ 表达式 'TimeSpan.Parse((EntityShaperExpression: 实体类型:我的 值缓冲区表达式: (ProjectionBindingExpression: EmptyProjectionMember( 可为空:假(。总登录时间(。总小时数"无法翻译。要么以可翻译的形式重写查询, 或通过插入对 AsEnumerable((、AsAsyncEnumerable((、ToList(( 或 ToListAsync((.请参阅 https://go.microsoft.com/fwlink/?linkid=2101038 更多信息。

溶液:

使用@Arcord提供的解决方案。 我不得不添加一个扩展方法来转换小时数,但这超出了这个原始问题的范围。

string logonHours = myObj.ToList().Sum(a => a.TotalLoggedInTime.ToHours()).ToString();
public static double ToHours(this string valueInTimeFormat)
{
double hours = 0;
//hours = TimeSpan.Parse(valueInTimeFormat).TotalHours;
int[] ssmmhh = { 0, 0, 0 };
var hhmmss = valueInTimeFormat.Split(':');
var reversed = hhmmss.Reverse();
int i = 0;
reversed.ToList().ForEach(x => ssmmhh[i++] = int.Parse(x));
hours = (int)(new TimeSpan(ssmmhh[2], ssmmhh[1], ssmmhh[0])).TotalHours;
return hours;
}

这是因为它试图将你的代码转换为SQL。

string logonHours = myObj.Sum(a => TimeSpan.Parse(a.TotalLoggedInTime).TotalHours).ToString();

当然,所有内容都不能转换为SQL,因此在这种情况下它会失败。

你可以使用这个:

string logonHours = myObj.ToList().Sum(a => TimeSpan.Parse(a.TotalLoggedInTime).TotalHours).ToString();

它应该有效,但".ToList(("将强制EF从数据库中获取所有数据,然后(因为所有内容都在内存中(可以应用代码。

但仅当您有少量数据时才这样做!如果您不知道预期的负载,最好不要将这种东西投入生产。

编辑

您还可以考虑存储"tick"而不是字符串(如此处所述(。在这种情况下,您将能够做到。

string logonHours = TimeSpan.FromTicks(myObj.Sum(a => a.TotalLoggedInTime)

将在 SQL 服务器上完成更多工作,您只会收集总和。

您还应该考虑使用"异步"版本的方法(ToListAsync,SumAsync,...(

最新更新