Entityframework Core 3 linq表达式无法翻译

时间:2019-12-18 23:42:36

标签: c# entity-framework-core

我刚刚升级到EF 3,我曾经使用过的查询之一现在给出了例外情况

   ProductionRecords = _context.ProductionRecords
          .Where(r => r.DataCriacao.Date == DateTime.Now.Date)
            .Select(pr => new ProductionRecordViewModel
            {
                Id = pr.Id,
                Operador = pr.Operador,
                DataCriacao = pr.DataCriacao,
                Celula = pr.Celula.Name,
                Turno = pr.Turno.Name,
                TotalPecasSemDefeito = pr.ReferenceRecords.Sum(c => c.Quantity),
                TotalPecasComDefeito = pr.DefectRecords.Sum(c => c.Quantidade),
                TotalTempoParado = pr.StopRecords.Sum(c => Convert.ToInt32(c.Duration.TotalMinutes)),
            })
          .AsNoTracking()
          .ToList();

当我尝试将集合与时间跨度和持续时间相加时,会发生异常。...

我现在应该如何处理?

这是个例外

  

InvalidOperationException:LINQ表达式   '(EntityShaperExpression:EntityType:StopRecord   ValueBufferExpression:(ProjectionBindingExpression:   EmptyProjectionMember)IsNullable:False).Duration.TotalMinutes'   无法翻译。可以使用以下形式重写查询:   进行翻译,或通过插入来明确切换到客户评估   调用AsEnumerable(),AsAsyncEnumerable(),ToList()或   ToListAsync()。有关详情,请参见https://go.microsoft.com/fwlink/?linkid=2101038   更多信息。

2 个答案:

答案 0 :(得分:3)

与其尝试教EF Core如何计算时间跨度,不如向数据库添加计算列吗?

        public TimeSpan Duration { get; set; }
        public int Minutes { get; }


        entity.Property(e => e.Minutes)
            .HasComputedColumnSql("DATEDIFF(MINUTE, 0, Duration)");

答案 1 :(得分:2)

EF3中发生了重大变化,除非在查询链的最末端(您的Convert.ToInt32(c.Duration.TotalMinutes)可能依赖),否则EF3不会自动恢复为客户端评估。

尝试像这样重写查询:

 ProductionRecords = _context.ProductionRecords
      .Where(r => r.DataCriacao.Date == DateTime.Now.Date)
        .AsNoTracking()
        .AsEnumerable()
        .Select(pr => new ProductionRecordViewModel
        {
            Id = pr.Id,
            Operador = pr.Operador,
            DataCriacao = pr.DataCriacao,
            Celula = pr.Celula.Name,
            Turno = pr.Turno.Name,
            TotalPecasSemDefeito = pr.ReferenceRecords.Sum(c => c.Quantity),
            TotalPecasComDefeito = pr.DefectRecords.Sum(c => c.Quantidade),
            TotalTempoParado = pr.StopRecords pr.StopRecords.Sum(c => Convert.ToInt32(c.Duration.TotalMinutes)),
        })
      .ToList();

UPD 正如评论中已正确指出的那样-这基本上会将.Select评估推迟到客户端。这可能会导致性能问题。此行为很可能是首先对EF Core 3进行了此更改的原因。

我没有足够的细节向您推荐合适的解决方案,但是似乎您无法摆脱对所有结果加载StopRecords的麻烦。编写自定义方法转换器可以为您提供帮助。有关如何操作的信息,请参见我的other answer。我迅速检查了EF Core 3的来源,看来IMethodCallTranslator仍然存在。这意味着您很有可能建立一个自定义函数,该函数将在SQL中将日期转换为TotalMinutes。