没有值的 Linq 计数列表 InvalidOperationException

Linq Count List InvalidOperationException on no values

我正在尝试通过注入了 DbContext 的范围后台服务获取过去一小时内的签到数量。

以下查询按预期工作。

var checkins = _dbContext.CheckIns.ToList();
var checkinList = checkins.Where(x => x.LogInTimeStamp.ToUniversalTime() > DateTime.UtcNow.AddHours(-1));
var checkinCount = checkins.Count(x => x.LogInTimeStamp.ToUniversalTime() > DateTime.UtcNow.AddHours(-1));

因为我想保持干净,所以我试着把它写成一行:

var oneLineCountTest = _dbContext.CheckIns.Count(x => x.LogInTimeStamp.ToUniversalTime() > DateTime.UtcNow.AddHours(-1));
var oneLineCountTest2 = (int?)_dbContext.CheckIns.Count(x => x.LogInTimeStamp.ToUniversalTime() > DateTime.UtcNow.AddHours(-1)) ?? 0;

这两行 return 来自 EFCore 的 InvalidOperationException,我不明白为什么。有人有解释或解决方案吗?

Exception thrown: 'System.Net.Sockets.SocketException' in System.Net.Sockets.dll
Exception thrown: 'System.OperationCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.OperationCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.OperationCanceledException' in System.Net.Http.dll
Exception thrown: 'System.OperationCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Net.Http.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Net.Http.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Net.Http.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.InvalidOperationException' in Microsoft.EntityFrameworkCore.dll

谢谢

注意本地查询 (Linq to Objects) 和解释查询 (Linq to Entities) 之间的区别。

您的第一个代码片段(有效的代码片段)使用解释查询来构建列表。 您向数据库引擎请求一组元素,它们将被返回并具体化为一个列表(ToList() 调用执行具体化)。 然后本地查询对该列表起作用,这是可能的,因为该列表是本地对象(在内存中)。

第二个代码片段不同。您只执行解释查询(使用 Linq to Entities)。 这意味着您要求数据库引擎执行所有查询:计算满足特定规则的元素数量。 只有当 Linq to Entities 能够将 SQL 中的查询转换为由数据库引擎执行时,它才会起作用。 这可能在这里失败。
罪魁祸首可能是使用了 AddDays() 方法(请参阅末尾的第一个 link)。

记住:

  • Linq to Object 使用委托在 IEnumerable 上工作。
  • Linq to Entities 使用表达式树在 IQueryable 上工作。

因此,在您的情况下,解释查询中使用的代码可能无法转换为 SQL。

要检查这一点,请尝试简化(即使它没有功能意义)用作 Count 参数的 lambda 中的代码,看看是否没有更多异常。

见:

  • Add Day to DateTime in EF Core 3 when Select executed
  • Linq-to-EF DateTime.ToLocalTime not supported

如果您尝试此查询,它不会发出任何异常

var dateTimeNow= DateTime.AddHours(-1);

Var oneLineCountTest = _dbContext.CheckIns.Count(x => x.LogInTimeStamp > DateTimeNow);

这意味着 EF translatore 无法将 ToUniversalTime() 转换为 SQL 脚本,这就是您遇到的例外情况。使用 ToList() 后,所有数据都将移至 Web 服务器,您可以使用任何对 c# 合法的代码。 我认为既然你使用的是时间差,而不是时间,你可以在不转换为 UTC 时间的情况下计算时间差,如果你的应用程序没有在世界各地使用的话。