EF Core 2.1 RC 1 GroupBy仍然在本地进行评估

时间:2018-05-15 21:39:53

标签: c# .net-core entity-framework-core

我按照ASP.NET博客中的official guide将ASP.NET Core项目从 2.0.x 升级到 2.1.0-rc1 EF Core 包也更新为相同版本。我使用的数据库提供程序是Microsoft.EntityFrameworkCore.SqlServer。我正在等待这次升级,因为我需要很多LINQ GroupBy translation功能。我的一个疑问如下:

await _db.Documents
         .ApplyFilter(options)
         .Where(x => x.SubscriptionId == subscriptionId && x.Status != DocumentStatus.Deleted)
         .GroupBy(document => new { document.SubscriptionId })
         .Select(group => new {
            Total = group.Sum(x => x.Total),
            TotalDiscount = group.Sum(x => x.TotalDiscount),
            TotalNet = group.Sum(x => x.TotalNet != null ? x.TotalNet.Value * (decimal)x.CurrencyRate : 0),
            SubTotal = group.Sum(x => x.SubTotal != null ? x.SubTotal.Value * (decimal)x.CurrencyRate : 0),
            TotalSalesTax = group.Sum(x => x.TotalSalesTax != null ? x.TotalSalesTax.Value * (decimal)x.CurrencyRate : 0),
            TotalTax = group.Sum(x => x.TotalTax != null ? x.TotalTax.Value * (decimal)x.CurrencyRate : 0),
            TotalPayable = group.Sum(x => x.TotalPayable != null ? x.TotalPayable.Value * (decimal)x.CurrencyRate : 0)
        })
        .ToListAsync();

当此查询运行时,我仍会收到一条警告:

  

EFCore Linq查询无法翻译,将在本地进行评估。

所以我想问一下,如果我做某事(非常)错了,或者这个功能还没有公布,那么这个功能还没有?你有没有尝试过类似的东西?提前感谢您的帮助。

修改

对于测试的摇晃,尝试将以下查询(从Sum方法中移除条件检查)作为 Ivan Stoev 在评论中建议,但结果是相同的。

await _db.Documents
         .ApplyFilter(options)
         .Where(x => x.SubscriptionId == subscriptionId && x.Status != DocumentStatus.Deleted)
         .GroupBy(document => new { document.SubscriptionId })
         .Select(group => new {
            Total = group.Sum(x => x.Total),
            TotalDiscount = group.Sum(x => x.TotalDiscount),
            TotalNet = group.Sum(x => x.TotalNet),
            SubTotal = group.Sum(x => x.SubTotal),
            TotalSalesTax = group.Sum(x => x.TotalSalesTax),
            TotalTax = group.Sum(x => x.TotalTax),
            TotalPayable = group.Sum(x => x.TotalPayable)
          })
          .ToListAsync();

解决方案

经过实验,我发现了以下几点。我发布它以防有人有同样的问题。以下查询完美地转换为T-SQL语句,因此不在客户端上进行评估。

await (from d in _db.Documents.ApplyFilter(options)
       where d.SubscriptionId == subscriptionId && d.Status != DocumentStatus.Deleted
       group d by d.SubscriptionId into g
       select new {
          Total = g.Sum(x => x.Total/* * Convert.ToDecimal(x.CurrencyRate)*/),
          TotalDiscount = g.Sum(x => x.TotalDiscount/* * Convert.ToDecimal(x.CurrencyRate)*/),
          TotalNet = g.Sum(x => x.TotalNet/* * Convert.ToDecimal(x.CurrencyRate)*/),
          SubTotal = g.Sum(x => x.SubTotal/* * Convert.ToDecimal(x.CurrencyRate)*/),
          TotalSalesTax = g.Sum(x => x.TotalSalesTax/* * Convert.ToDecimal(x.CurrencyRate)*/),
          TotalTax = g.Sum(x => x.TotalTax/* * Convert.ToDecimal(x.CurrencyRate)*/),
          TotalPayable = g.Sum(x => x.TotalPayable/* * Convert.ToDecimal(x.CurrencyRate)*/)
       }).ToListAsync();

明显的区别在于我使用 LINQ查询语法而不是扩展方法。此外,我将CurrencyRate属性的乘法注释为,这也导致在本地评估查询。这看起来很奇怪,因为查询语法也可以在扩展方法中进行翻译。

我还在Entity Framework Core的Github存储库中打开了一个问题  您可以找到here

2 个答案:

答案 0 :(得分:0)

GroupBy是一只红鲱鱼。

使用查询语法编译为使用扩展方法,这不是问题。

我在编辑版本和查询语法版本之间可以看到的唯一区别是,在仍然在本地评估group by的情况下,您会_db.Documents.ApplyFilter(...)。我猜这会导致返回类型转移到其他东西,并且选择了错误的重载,或者一些混淆查询转换器的类似细节 - 这将导致所有的LINQ运算符( Where,Select,GroupBy等在本地进行评估。

答案 1 :(得分:0)

在我的情况下,此查询在客户端评估了分组:

await context.MyCollection
.GroupBy(x => x.Tag.Id)
.ToDictionaryAsync(x => x.Key, x => x.Count());

将其更改为以下内容可使其在服务器端进行评估:

await context.MyCollection
.GroupBy(x => x.Tag.Id)
.Select(g => new {g.Key, Count = g.Count()})
.ToDictionaryAsync(arg => arg.Key, arg => arg.Count);