Переход с EF Core 2 на EF Core 3 - PullRequest
       50

Переход с EF Core 2 на EF Core 3

6 голосов
/ 30 сентября 2019

После обновления моего проекта с (dotnet core 2 / ef core 2) до (dotnet core 3 / ef core 3) почти все запросы LINQ моей структуры сущностей прерываются. хотя я уже прочитал этот , все еще неясно, что делать.

Вот несколько примеров, с которыми у меня возникают проблемы:

var league = await dbContext.League.LastAsync();

Хотя этот код работал простонормально в ef core 2 он выдает исключение в ef core 3. Единственный обходной путь, который я смог найти по этому поводу, был следующий код, который все еще не тот, который я хочу, так как он не асинхронный, как раньше.

var league = dbContext.League.AsEnumerable().Last();

Другой примерто же исключение выдает следующий код:

var user = await dbContext.User.FirstOrDefaultAsync(u =>
                u.UserId == userId && string.Equals(u.Token, token, StringComparison.InvariantCulture));

Я все еще могу использовать AsEnumerable (), но асинхронная версия FirstOrDefault там недоступна, так что это не вариант. кто-нибудь может направить меня с этим?

РЕДАКТИРОВАТЬ
Вот исключение:

System.InvalidOperationException: The LINQ expression 'Last<League>(DbSet<League>)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

Ответы [ 2 ]

6 голосов
/ 01 октября 2019

Ответ на ваш вопрос будет действительно многословным, поскольку он соответствует некоторым другим изменениям, произошедшим в EF Core 3.0;Итак, давайте просто рассмотрим небольшую его часть.

Как вы упомянули в своем вопросе, у Microsoft есть несколько запутанное описание изменений в версии 3.0 в этом посте .

Первая часть вышеприведенного сообщения: « LINQ-запросы больше не оцениваются на клиенте ». Там написано, что раньше разработчики писали запросы, состоящие из двух частей;Одна часть - это запрос к базе данных, а другая - выражение, известное только для клиентского кода. В этой ситуации client evaluation of potentially expensive expressions only triggered a warning. Но в новой версии ядро ​​EF позволяет только последнему вызову Select () быть оцененным на клиенте и генерирует исключение, когда есть выражения, которые нельзя преобразовать ни в SQL, ни в параметр.

Чтобы очистить этоВ заключение рассмотрим пример, описанный Диего Вегой в его сообщении в блоге EF Core 3.0 .

Явное переключение на оценку клиента : ЕслиВаш запрос фильтрует данные на основе выражения, которое не может быть переведено в SQL. Возможно, вам придется явно переключиться на оценку клиента, вставив вызов либо в AsEnumerable (), AsAsyncEnumerable (), ToList (), либо ToListAsync () в серединезапрос. Например, следующий запрос больше не будет работать в EF Core 3.0, поскольку один из предикатов в предложении where требует оценки клиента:

var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));

Но если вы знаете, что разумнообрабатывая часть фильтра на клиенте, вы можете переписать запрос следующим образом:

var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n)) 
    .AsEnumerable() // Start using LINQ to Objects (switch to client evaluation)
    .Where(c => IsSpecialCustomer(c));

В приведенном выше примере IsSpecialCustomer(c) - это метод, который не может быть преобразован в SQL, поскольку это метод C #, которыйэто доступно только в коде клиента. Таким образом, разработчики должны либо переписать запрос в форме, которую можно перевести, либо выполнить запрос к базе данных, а затем оценить результаты базы данных для клиента, используя .AsEnumerable(), а затем можно отфильтровать результаты на основе возвращенного значения IsSpecialCustomer(c). Вот почему вы все еще можете получить доступ к AsEnumerable() в своем коде.

Теперь давайте посмотрим, почему метод FirstOrDefaultAsync() недоступен?

Ну, естьдве причины, которые вызывают эту ситуацию.

Я ответил на первую причину раньше: код для обнаружения нескомпозиционного SQL был удален в версии 3.0.

И вторая: конвейер запросов делаетне понимаю асинхронные операторы с запросом в дереве выражений (например, когда вы пытаетесь получить к нему доступ в EF.CompileQuery()).

В общем, есть пара интересных сообщений, которые выможно прочитать:

40 критических изменений в ядре ef core 3

Объявление структуры ядра ядра 3.0, предварительный просмотр 9 и структуры объекта 6.3, предварительный просмотр 9

Проблемы с ядром EF на github

2 голосов
/ 01 октября 2019
  1. используйте OrderByDesc() для некоторого свойства, а затем FirstAsync(). (https://github.com/aspnet/EntityFrameworkCore/issues/18211)

  2. инвариантное сравнение не переведено, возможно, оно было оценено клиентом ранее. В зависимости от настроек сортировки базы данных вы, возможно, просто могли бы сделать здесь обычные равные.

Вызов AsEnumerable() на вашем DbSet без каких-либо фильтров приведет к удалению всех данных локально, а не к тому, что вы хотите делать в производственной среде. Попробуйте переписать код выше и отслеживать созданный SQL, чтобы убедиться, что вы получаете производительные запросы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...