2

我有这条线一直运行到我启用 RelationalEventId.QueryClientEvaluationWarning。

在这里,让我们说我想做的是根据他们的最新订单日期对结果(客户)进行排序。

.OrderByDescending(x=>x.orders.Max(y=>y.CreateDate))

在我如下配置上下文后,我意识到 Max() 没有转换为 TSql。

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    base.OnConfiguring(optionsBuilder);
    optionsBuilder.ConfigureWarnings(warning =>
    {
        warning.Throw(RelationalEventId.QueryClientEvaluationWarning);
    });
}

错误:

InvalidOperationException: Error generated for warning 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: The LINQ expression 'Max()' could not be translated and will be evaluated locally.

我假设在本地计算最大值不利于获得更好的性能。有没有办法计算 SQL Server 上的最大值?

4

2 回答 2

6

如果您启用了 EF Core日志记录,您将看到以下警告:

=> Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor

在子查询中可能意外使用可能引发的聚合方法(Min、Max、Average)。将使用客户端评估,如果不存在数据,则操作员将抛出。将子查询结果类型更改为可为空的类型将允许完全翻译。

基本上,他们试图在 LINQ to Objects 中保留上述聚合方法的抛出行为。

解决方案在最后一句话中。例如,如果类型CreateDateDateTime,那么

.OrderByDescending(x => x.orders.Max(y => (DateTime?)y.CreateDate))

将被翻译成 SQL。

于 2019-02-18T22:08:44.677 回答
4

当您在使用不可为空类型的 LINQ 查询中调用聚合方法(Average、Min、Max)时,它别无选择,只能在本地对其进行评估。

为避免这种情况,请将您的 Max 值转换为可为空的类型,它将在数据库中进行评估。

假设 CreateDate 是 DateTime 类型,将其转换为 DateTime?(可为空)应该工作。

您的查询应如下所示:

.OrderByDescending(x=>x.orders.Max(y=> (DateTime?)y.CreateDate)) 

此答案引用自官方 Github Repo

于 2019-02-18T20:58:04.127 回答