EFCore 3.1 - существует запрос через Any; Запрос не может быть переведен

Мы используем EFCore 3.1 и пытаемся построить запрос, используя Exists с помощью .Any(), который охватывает 2 свойства.

var selectionCriteria = someHugeList.Select(sh => new { sh.Id, sh.StatusCode }).ToList()
var resultsQry = _myContext.SomeClass
                           .Include(sc => sc.DetailRecords)
                           .Where(sc => selectionCriteria.Any(crit => crit.Id == sc.Id 
                                                                   && crit.StatusCode == sc.StatusCode));

var results = await resultsQry.ToListAsync()

При выполнении этого запроса (даже с небольшим количеством (5 элементов) элементов критериев выбора он выдает следующее сообщение об ошибке;

System.InvalidOperationException: выражение LINQ «DbSet .Where(c => __selectionCriteria_0 .Any(crit => crit.Id == sc.Id && crit.StatusCode == sc.StatusCode))» не может быть переведено. Либо перепишите запрос в форме, которую можно перевести, либо явно переключитесь на оценку клиента, вставив вызов AsEnumerable(), AsAsyncEnumerable(), ToList() или ToListAsync(). См. https://go.microsoft.com/fwlink/?linkid=2101038. Чтобы получить больше информации.'

Кажется, проблема заключается в том, что в предложении .Any есть 2 свойства. Где существует в sql обычно может сделать это без проблем. EFCore, кажется, находит это трудным.

Кто-нибудь знает, как это решить?


person Obelix    schedule 06.02.2020    source источник


Ответы (1)


только что нашел это; https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-на-клиенте

короче говоря; оценка клиента больше не работает в EFCore 3.1, что означает, что этот тип запроса (сравнение списка на стороне клиента со списком на стороне сервера) не работает. Вам нужно довести его до клиента. Мой коллега только что указал мне, что я не оценил весь потенциал сообщения об ошибке :).

Изменил мой запрос следующим образом (не оптимально, но другого решения пока нет):

var selectionCriteria = someHugeList.Select(sh => new { sh.Id, sh.StatusCode }).ToList()
var resultsQry = _myContext.SomeClass
                           .Include(sc => sc.DetailRecords)
                           .AsEnumerable() // this is the important part, pulling all the records client side so we can execute the .Any on the client.
                           .Where(sc => selectionCriteria.Any(crit => crit.Id == sc.Id 
                                                                   && crit.StatusCode == sc.StatusCode));

var results = await resultsQry.ToList() // no more async, because clientside
person Obelix    schedule 06.02.2020
comment
Вы можете изменить .AsEnumerable() .Where(sc => selectionCriteria.Any(crit => crit.Id == sc.Id && crit.StatusCode == sc.StatusCode)); на ..Where(sc => Ids.Contains(sc.Id) && Codes.Contains(sc.StatusCode)). Ids: список идентификаторов критериев, Codes: список кодов состояния и проверьте его, пожалуйста? - person Mohammed Sajid; 06.02.2020
comment
Комментарий @MohammedSajid совпадает с решением 3: в этом SO. Это потенциально может привести к передискретизации, но лучше всего перейти по ссылке и увидеть компромиссы. - person ttugates; 21.03.2021