Ef core 3 casting не может быть переведен - PullRequest
2 голосов
/ 10 октября 2019

Я хочу привести свой IQueryable к интерфейсу, подобному следующему:

public static IQueryable<T> _enableFilter<T>(this IQueryable<T> queryable) => queryable.Where(x => (x as IEnable).Enable);
_newsRepository.BaseQuery.EnableFilter().FirstOrDefaultAsync(x => x.Id == model.Id);

его работа на EF core 2.2, но в 3 я выдаю эту ошибку:

System.InvalidOperationException : The LINQ expression 'Where<News>(
    source: DbSet<News>, 
    predicate: (n) => (n as IEnable).Enable)' 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 ]

3 голосов
/ 10 октября 2019

Этот запрос также не работал в EF Core 2.2. Это приведение не имеет смысла в SQL - в SQL нет интерфейсов или наследования. У EF Core до 3-х была ... неудачная функция - оценка на стороне клиента. Если EF Core не сможет что-то перевести на SQL, он все потянет к клиенту и попытается отфильтровать там данные. Излишне говорить, что это пагубно для производительности. Хуже того, это было сделано без предупреждения. Предупреждение или исключение позволит вам распознать и устранить проблему. По крайней мере, в EF Core 2.2 можно было отключить оценку на стороне клиента. В EF Core 3 это ушло навсегда.

Что касается самого метода, то вам вообще не понадобится это приведение, если вы используете ограничение типа, например:

public static IQueryable<T> _enableFilter<T>(this IQueryable<T> queryable) 
    where T:IEnable 
{
    return queryable.Where(x => (x as IEnable).Enable);
}

Я не уверен, что EF Core примет это - это необычный синтаксис. Намного проще просто добавить это дополнительное условие, например:

_newsRepository.BaseQuery.EnableFilter().FirstOrDefaultAsync(x => x.Id == model.Id && x.Enabled);

Global Queries и Soft удаляет

Если вы хотите применить условие фильтра ко всем запросамиспользуя конкретную сущность, например, для программного удаления, вы можете использовать глобальные фильтры . Фактически, soft-delete является первым сценарием, упомянутым в документации.

В вашем контексте OnModelCreating() метод, который вы можете добавить:

modelBuilder.Entity<SomeEntity>().HasQueryFilter(p => p.IsEnabled);
2 голосов
/ 10 октября 2019

Причиной этого является изменение того, как EF Core 3 обрабатывает подобные ситуации.

В EF core 2.x это было занесено в память, и операция выполнялась там автоматически из-за потенциальных проблем с производительностью. Делая подобные вещи, основная команда EF приняла решение перевести его из поведения по умолчанию в ошибку, являющуюся поведением по умолчанию.

По сути, если вам нужно то же поведение, что и в 2.x, вы теперьЯ должен явно вытянуть его в память, прежде чем делать это - однако, это часто может быть признаком того, что, вероятно, лучше изменить способ выполнения вашего запроса - если вам действительно не нужно явно это поведение

Для получения дополнительной информации осм. Здесь

...