Выражение LINQ «DbSet <Entity>.Where (p => p.IsValid)» не может быть переведено в EF Core 3 - PullRequest
0 голосов
/ 02 февраля 2020

Прежде всего я знаю о критических изменениях в EF Core 3, как описано в https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq -запросы «больше не оцениваются на клиенте»

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

var posts = await _applicationDbContext.Posts
            .Include(p => p.Account)
            .Include(p => p.Recording)
            .Where(p => p.AccountId == accountId && p.Type == postType && p.IsValid)
            .OrderByDescending(p => p.Occured)
            .ToListAsync();

Создание исключения

System.InvalidOperationException: выражение LINQ 'DbSet .Where (p = > p.AccountId == __accountId_0 && (int) p.Type == (int) __ postType_1 && p.IsValid) 'не удалось перевести. Либо переписайте запрос в форме, которую можно перевести, либо переключитесь на оценку клиента явно, вставив вызов либо в AsEnumerable (), AsAsyncEnumerable (), ToList (), либо в ToListAsyn c (). См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации.

Реализация IsValid выглядит следующим образом:

public bool IsValid => Status == PostStatus.Active && Recording.IsValid
public bool IsValid => Status == RecordingStatus.Active;

Теперь, если я изменю запрос на:

var posts = await _applicationDbContext.Posts
        .Include(p => p.Account)
        .Include(p => p.Recording)
        .Where(p => p.AccountId == accountId && p.Type == postType && p.Status == PostStatus.Active && p.Recording.Status == RecordingStatus.Active)
        .OrderByDescending(p => p.Occured)
        .ToListAsync();

Работает и преобразуется в sql, как и ожидалось. Естественно, я мог бы go со второй реализацией, но есть очевидные преимущества наличия реализации IsValid в одном месте. Я также не хочу пропустить проверку IsValid в запросе, чтобы сделать это в памяти позже по понятным причинам. Я что-то здесь упускаю?

1 Ответ

0 голосов
/ 02 февраля 2020

Я все еще думаю, что ребята из EF могли бы сделать это по-другому, но в любом случае из приведенного выше комментария Progman, ссылающегося на этот вопрос о переполнении стека , можно получить обходной путь, выглядящий примерно так:

public static Expression<Func<Post, bool>> IsValid => post => post.Status == PostStatus.Active && post.Recording.Status == RecordingStatus.Active;

А затем назовите его следующим образом:

var posts = await _applicationDbContext.Posts
    .Include(p => p.Account)
    .Include(p => p.Recording)
    .Where(p => p.AccountId == accountId && p.Type == postType)
    .Where(Post.IsValid)
    .OrderByDescending(p => p.Occured)
    .ToListAsync();

Таким образом вы избегаете дублирования кода и в некоторой степени придерживаетесь хороших практик.

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