Оба запроса возвращают неверные результаты.
Сгенерированный EF Core SQL-запрос возвращает [1, 5, 6].
Рукописный SQL-запрос (который эквивалентен использованию Any
вместо All
и будет также сгенерирован EF Core, если вы это сделаете) возвращает [1, 2, 4].
И желаемый результат - [1].
Во-первых, это общеизвестный факт, что
All(condition)
- это то же самое, что (эквивалент)
!Any(!condition)
Второй факт (и это легко увидеть), что оба выражения возвращаютtrue
когда последовательность пуста (не имеет элементов).Что технически правильно - все (в данном случае ноль) элементы соответствуют условию.Или нет элемента, не соответствующего условию.
Но в вашем случае это не работает, потому что вы на самом деле хотите "получить месяцы, для которых существует загрузка и загрузка успешна для все типы загрузки ", что выражается как:
.Where(e => e.UploadDetails.Any()
&& e.UploadDetails.All(o => o.UploadStatusId == 3))
или" существует успешная загрузка и не существует неудачной загрузки ", выраженное как:
.Where(e => e.UploadDetails.Any(o => o.UploadStatusId == 3)
&& !e.UploadDetails.Any(o => o.UploadStatusId != 3))
Оба эти условия будутпроизвести желаемое поведение.Тем не менее, они будут генерировать 2 коррелированных подзапроса для выполнения проверки.
Если вы хотите выполнить проверку только одним коррелированным подзапросом (который не гарантирует, что запрос будет быстрее - его нужно измерить), вы можете использовать следующий прием:
.Where(e => e.UploadDetails.Min(o => o.UploadStatusId == 3 ? 1 : (int?)0) == 1)
Используется тот факт, что функция Min<int?>
возвращает null
, когда последовательность не имеет элементов.Это, плюс логика условия внутри, гарантирует, что она вернет 1
только тогда, когда есть элементы, соответствующие условию, и нет элементов, не соответствующих ему.Что именно то, что нам нужно.