我已经学习了在EF Core 3.0中进行客户端评估can only happen on the top level projection(即对Select的最后一次调用)的艰难方法。我以为我理解了这个问题,但是一个查询的失败(尤其是在3.1下)告诉我我没有。
这是查询
using (var ctx = new GsContext())
{
var recs = ctx.Calibrations
.Where(ca => ca.DeviceId == deviceId)
.AsNoTracking()
.Include(c => c.Cartridge)
.OrderByDescending(i => i.CalibratedOn)
.GroupBy(r => r.CartridgeId)
.Select(q => q.First())
.ToList();
我看不到自己做任何复杂的预测或在选择之前需要客户端评估的任何事情,因此异常消息使我感到困惑。这是错误消息的文本:
LINQ表达式'(GroupByShaperExpression:KeySelector:[c.CartridgeId),ElementSelector:(EntityShaperExpression:EntityType:校准ValueBufferExpression:(ProjectionBindingExpression:空投影成员)IsNullable:False)).First()'无法翻译。以可以翻译的形式重写查询,或显式切换到客户端评估通过插入对AsEnumerable(),AsAsyncEnumerable()的调用,ToList()或ToListAsync()。看到https://go.microsoft.com/fwlink/?linkid=2101038了解更多信息。
在查询试图在查询的早期进行一些复杂的字符串处理之前,我就已经遇到过类似的异常(就像我说过的那样,我是通过困难的方式来了解这个问题的,但是在这里情况并非如此)至少我看不到。
我找到了this related question,但在这种情况下,该家伙正在GroupBy子句中进行投影。我没那么做
如果有帮助,这里是校准类
public class Calibration
{
[Key]
[Required]
public int Id { get; set; }
[Required]
public int DeviceId { get; set; }
[Required]
public int CartridgeId { get; set; }
[ForeignKey(nameof(CartridgeId))]
public Cartridge Cartridge { get; set; }
public DateTime CalibratedOn { get; set; }
}
我确定我可以解决此问题。我要求更好地了解客户端/服务器评估。有人可以向我解释我所缺少的吗?我的查询需要客户评估吗
我找到了this related question,但在这种情况下,该家伙正在GroupBy子句中进行投影。我没有这样做。
嗯,这就是问题所在,在我写的链接文章的my answer中:
的投影在不幸的是,当前的EF Core 3.0 / 3.1 仅支持 GroupBy的服务器翻译(类似于SQL)。
换句话说,您必须
GroupBy
之后仅包含键和/或聚合,否则它将无法转换。 Here是相关的GitHub问题。以及Complex Query Operators - GroupBy下官方文档的一些解释:LINQ GroupBy运算符创建类型为IGrouping<TKey, TElement>
的结果,其中TKey
和TElement
可以是任意类型。此外,IGrouping
实现了IEnumerable<TElement>
,这意味着您可以在分组后使用任何LINQ运算符对其进行合成。由于没有数据库结构可以表示IGrouping
,因此GroupBy运算符在大多数情况下没有转换。将聚合运算符应用于每个返回标量的组时,可以将其转换为关系数据库中的SQLGROUP BY
。 SQLGROUP BY
也是限制性的。它要求您仅按标量值分组。投影只能包含分组键列或应用于列的任何聚合。