Entity Framework 3.0 Contains не может быть переведен в SQL, как это было в EF Core 2.2 - PullRequest
1 голос
/ 04 ноября 2019

Я пытаюсь перенести Web API с .NET Core 2.2 на .NET Core 3.0, и я наткнулся на следующее:

public Dictionary<int, Tag> GetTagMap(IList<int> tagIds = null)
{
    var tags = context.Tag.AsNoTracking();
    if (tagIds != null)
        tags = tags.Where(t => tagIds.Contains(t.TagId));

    return tags
       .ToList()       // explicit client evaluation in 3.0
       .ToDictionary(t => t.TagId, t => t);
}

Это используется для генерации оператора SQL, подобного этому:

SELECT TagId, Name FROM Tag WHERE TagId IN (1, 2, 3)

, который очень хорошо работал для правильно проиндексированного столбца и небольшого числа значений IN.

Теперь я получаю следующую ошибку, предполагающую, что перевод List<>.Contains больше не поддерживается:

System.InvalidOperationException: 'выражение LINQ' Где (источник: DbSet, предикат: (t) => (необработанный параметр: __tagIds_0) .Contains (t.TagId)) 'не удалось перевести,Либо переписать запрос в форме, которую можно перевести, либо явно переключиться на оценку клиента, вставив вызов либо AsEnumerable (), AsAsyncEnumerable (), ToList (), либо ToListAsync (). Для получения дополнительной информации см. Оценка клиента и сервера - EF Core. '

Это говорит о том, что запросы LINQ больше не оцениваются на клиенте прерывистое изменение, но AFAIK Contains былне оценивается на клиенте.

Ответы [ 2 ]

2 голосов
/ 04 ноября 2019

Это ошибка 3.0, отслеживаемая # 17342: Содержится в универсальном IList / HashSet / ImmutableHashSet, вызывает исключение .

Уже исправлено в 3.1. Обходной путь (если вы не можете ждать) - принудительное использование Enumerable.Contains, например

t => tagIds.AsEnumerable().Contains(t.TagId)

или изменение типа переменной.

0 голосов
/ 04 ноября 2019

Я понял, что происходит, и почему мой код не работает должным образом (оценка на стороне сервера), и почему явная оценка на стороне клиента на самом деле очень хорошая вещь:

IList<T>.Contains действительно оценивался наклиент, но List<T>.Contains оценивается на стороне сервера. Простая замена IList на List заставила код работать без явной оценки клиента:

public Dictionary<int, Tag> GetTagMap(List<int> tagIds = null)
{
    var tags = context.Tag.AsNoTracking();
    if (tagIds != null)
        tags = tags.Where(t => tagIds.Contains(t.TagId));

    return tags
       .ToList()       // explicit client evaluation in 3.0
       .ToDictionary(t => t.TagId, t => t);
}
...