Допустим, у меня есть компании, у которых есть клиенты, у которых есть заказы. В одном поисковом запросе я хочу установить порядок таким образом, чтобы «компании с последними заказами были первыми». (Надеюсь, это достаточно ясно).
.OrderByDescending(x =>
x.Customers.Max(c => c.Orders.Any() ?
y.Orders.Max(o => (DateTime?) o.DateCreatedUtc)
: DateTime.MinValue)
)
В настоящее время я получаю это предупреждение: Выражение LINQ «Max()» не может быть переведено и будет оцениваться локально.
Можем ли мы переписать это для оценки на сервере?
Спасибо @IvanStoev. Мне было интересно, связана ли проблема с max в более глубоком дочернем элементе.
Пожалуйста. На самом деле вложенный Max может не работать из-за другого текущего ограничения EFC, но SelectMany должен. Если это не так, дайте мне знать, чтобы снова открыть вопрос.
SelectMany сделал свое дело. Потрясающий!





Изначально (приношу свои извинения) он выглядит точно так же, как используя Max() в Orderby — убедитесь, что вы используете обнуляемые перегрузки внешних (по сути, всех) вызовов Max / Min, и вы получите перевод.
Использование обнуляемых перегрузок по-прежнему необходимо. Однако здесь есть скрытая ловушка. - в настоящее время EF Core может преобразовывать агрегатные методы, только если они используют простой селектор элементов с необязательным приведением. Любое другое выражение вызывает оценку клиента независимо от того, допускает ли тип значение NULL или нет.
К счастью, есть простое решение, которое работает для всех стандартных агрегатов, кроме Average, — свести агрегатный набор с помощью SelectMany (может быть несколько и их можно комбинировать со свойствами ссылки) до уровня, содержащего агрегирующий объект, и применить агрегатную функцию к этому набору. .
Также убедитесь, что внутри агрегатного селектора не используются условные или подобные выражения. Преимущество обнуляемых перегрузок Max/Min заключается в том, что они возвращают null для пустого набора, поэтому нет необходимости включать проверки Any. nulls обычно идут первыми в порядке, поэтому обычно вам не нужны специальные значения дозорных. И даже если они вам нужны, обязательно примените их с помощью оператора C# ??после для агрегированного вызова.
С учетом всего сказанного, переводимая версия образца фрагмента
.OrderByDescending(x =>
x.Customers.SelectMany(c => c.Orders).Max(o => (DateTime?)o.DateCreatedUtc))
// ^ ^
// drill down convert to nullable
Это точно так же, как ваш предыдущий вопрос. Убедитесь, что внешний
Max(и любойMax) использует обнуляемую перегрузку, например.x.Customers.Max(c => c.Orders.Max(o => (DateTime?) o.DateCreatedUtc)). Илиx.Customers.SelectMany(c => c.Orders).Max(o => (DateTime?) o.DateCreatedUtc)