从EF Core中的子实体获取最大值

时间:2019-02-19 15:55:43

标签: c# entity-framework entity-framework-core ef-core-2.2

比方说,我有一些公司,这些公司的客户都有订单。 在一个搜索查询中,我希望以“带最新订单的公司优先”的方式设置订单。 (希望这很清楚)。

.OrderByDescending(x =>
x.Customers.Max(c => c.Orders.Any() ? 
        y.Orders.Max(o => (DateTime?) o.DateCreatedUtc) 
        : DateTime.MinValue)
) 
  • 如果客户没有订单,则将最新的订单日期视为DateTime.MinValue

目前,我收到以下警告: LINQ表达式'Max()'无法翻译,将在本地计算

我们可以重写它以便在服务器上进行评估吗?

1 个答案:

答案 0 :(得分:2)

一开始(我道歉),它看上去与using Max() in Orderby完全相同-确保您使用外部(基本上每个)Max / Min调用可为空的重载,并获得翻译。< / p>

仍然必须使用可为空的重载。但是,这里有一个隐藏的陷阱。 -当前,EF Core只有在使用简单成员选择器和可选强制转换的情况下才能转换聚合方法。任何其他表达式都会导致客户端评估,而不管类型是否可为空。

幸运的是,有一个简单的解决方案适用于除Average以外的所有标准聚合-使用SelectMany(可以多个,可以与参考导航属性组合)将聚合集展平到聚合实体,然后将聚合函数应用于该集合。

还要确保不在聚合选择器内使用条件表达式或类似表达式。可空Max / Min重载的好处在于,它为空集返回null,因此不需要包含Any检查。 null通常排在第一位,因此通常不需要特殊的哨兵值。而且即使您确实需要它们,也请确保在聚合调用之后使用C#??运算符 来应用它们。

话虽如此,示例代码段的可翻译版本是

.OrderByDescending(x => 
    x.Customers.SelectMany(c => c.Orders).Max(o => (DateTime?)o.DateCreatedUtc))
//                  ^                                  ^
//               drill down                    convert to nullable