求和和分组时,EF Core 2.1在本地评估

时间:2019-08-27 10:51:16

标签: entity-framework .net-core entity-framework-core ef-core-2.1

我正在使用EF Core 2.1,并且查询在SQL Server端不进行评估。

此查询中使用的模型为:

public class V_TurnoverByDivision
{      
    public long Id { get; set; }
    public decimal LineAmount { get; set; }
    public DateTime? PostingDate { get; set; }
    public decimal Quantity { get; set; }
    public decimal UnitCostLcy { get; set; }
    public string DivisionCode { get; set; }
    public string DivisionDescription { get; set; }
    public string TopDivisionCode { get; set; }
    public string TopDivisionDescription { get; set; }
    public decimal RUCAmount { get; set; }
}

此LINQ语句在SQL Server中完全运行:

return query
  .GroupBy(g => new { g.DivisionCode, g.DivisionDescription, g.TopDivisionCode, g.TopDivisionDescription, g.PostingDate })
  .Select(s =>
                    new V_TurnoverByDivision
                    {
                        DivisionCode = s.Key.DivisionCode,
                        DivisionDescription = s.Key.DivisionDescription,
                        TopDivisionCode = s.Key.TopDivisionCode,
                        TopDivisionDescription = s.Key.TopDivisionDescription,
                        PostingDate = s.Key.PostingDate,
                        LineAmount = s.Sum(ss => ss.LineAmount),
                        RUCAmount = s.Sum(ss => ss.LineAmount - (ss.Quantity * ss.UnitCostLcy))
                    });

并生成以下SQL

选择     [v]。[BIInvCNLinesID]    ,[v]。[DivisionCode]    ,[v]。[DivisionDescription]    ,[v]。[LineAmount]    ,[v]。[PostingDate]    ,[v]。[数量]    ,[v]。[TopDivisionCode]    ,[v]。[TopDivisionDescription]    ,[v]。[UnitCostLcy] 从[V_TurnoverByDivision] AS [v] 在[v]。[PostingDate]> = @__ firstDayOfcurrentMonth_0 ORDER BY [v]。[DivisionCode],[v]。[DivisionDescription],[v]。[TopDivisionCode],[v]。[TopDivisionDescription],[v]。[PostingDate]

此LINQ语句有效,但在内存中执行GroupBy

在“输出”窗口中出现警告

Microsoft.EntityFrameworkCore.Query:警告:LINQ表达式'Sum()'无法翻译,将在本地进行评估。

但我何时使用此查询

                  return query
                .GroupBy(g => new { g.DivisionCode, g.DivisionDescription, g.TopDivisionCode, g.TopDivisionDescription, g.PostingDate })
                .Select(s =>
                    new V_TurnoverByDivision
                    {
                        DivisionCode = s.Key.DivisionCode,
                        DivisionDescription = s.Key.DivisionDescription,
                        TopDivisionCode = s.Key.TopDivisionCode,
                        TopDivisionDescription = s.Key.TopDivisionDescription,
                        PostingDate = s.Key.PostingDate,
                        LineAmount = s.Sum(ss => ss.LineAmount)
                    });
            };

,SQL生成的查询应为:

选择     [v]。[DivisionCode]    ,[v]。[DivisionDescription]    ,[v]。[TopDivisionCode]    ,[v]。[TopDivisionDescription]    ,[v]。[PostingDate]    ,SUM([v]。[LineAmount])AS [LineAmount] 从[V_TurnoverByDivision] AS [v] 在[v]。[PostingDate]> = @__ firstDayOfcurrentMonth_0 GROUP BY [v]。[DivisionCode]         ,[v]。[DivisionDescription]         ,[v]。[TopDivisionCode]         ,[v]。[TopDivisionDescription]         ,[v]。[PostingDate]

如何解决问题宽度

RUCAmount = s.Sum(ss => ss.LineAmount-(ss.Quantity * ss.UnitCostLcy))

1 个答案:

答案 0 :(得分:2)

这是EF Core GroupBy的翻译限制(可能会在将来的某些版本中解决)。为了能够转换为SQL,聚合方法表达式应该是简单的属性访问器。

这就是为什么

s.Sum(ss => ss.LineAmount)

翻译,但是

s.Sum(ss => ss.LineAmount - (ss.Quantity * ss.UnitCostLcy))

没有。

因此,解决方案是预先选择聚合所需的表达式。一种方法是对元素选择器使用GroupBy重载:

return query
   .GroupBy(e => new // Key
   { 
       e.DivisionCode,
       e.DivisionDescription,
       e.TopDivisionCode,
       e.TopDivisionDescription,
       e.PostingDate
   },
   e => new // Element
   {
       e.LineAmount,
       RUCAmount = e.LineAmount - (e.Quantity * e.UnitCostLcy) // <--
   })
  .Select(g => new V_TurnoverByDivision
  {
      DivisionCode = g.Key.DivisionCode,
      DivisionDescription = g.Key.DivisionDescription,
      TopDivisionCode = g.Key.TopDivisionCode,
      TopDivisionDescription = g.Key.TopDivisionDescription,
      PostingDate = g.Key.PostingDate,
      LineAmount = g.Sum(e => e.LineAmount),
      RUCAmount = g.Sum(e => e.RUCAmount) // <--
  });