Почему SequenceEqual для ошибки перехвата списка?

#c# #.net-core #entity-framework-core #linq-to-entities

#c# #.net-ядро #сущность-фреймворк-ядро #linq-to-entities

Вопрос:

у меня есть объект с именем schoolrep, и этот schoolrep содержит много идентификаторов уровня образования, мой запрос linq выдает ошибку

Указанные критерии фильтрации были недействительными

введите описание изображения здесь

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

ниже приведен фильтр, я пытаюсь сделать его фиксированными значениями для тестирования

             List<long> lst = new List<long> { 1, 2, 3 };
  

ниже приведено выражение

             Expression <Func<SchoolRepresentative, bool>> filterExpression = x =>
            x.SchoolRepEducationLevels.Select(x=>x.EducationLevelId).SequenceEqual(lst)
  

Комментарии:

1. Короткий ответ — это не поддерживается.

2. как я могу справиться с этой проблемой

3. На концептуальном уровне поймите, что написать SQL для этого сложно. Затем, как только вы примете это, поймите, что именно поэтому он не поддерживается. 🙂

4. На практике это означает, что вам, скорее всего, нужно будет сделать это в памяти, а не в БД (т. Е. Вытащить все это, затем выполнить SequenceEqual локально).

5. schoolrep, у которого есть все уровни образования, отправленные в filter, но SequnceEquals этого не делает, он делает больше.

Ответ №1:

Это означает, что EF не поддерживает SequenceEquals метод при переводе вашего запроса в SQL.

Я не знаю, существует ли эквивалентный компактный SQL-запрос (найдите все объекты, где его единственные дочерние объекты имеют идентификаторы 1, 2 и 3).

Одним из вариантов было бы загрузить все объекты, у которых есть дочерний элемент 1, 2 или 3, используя x => lst.Contains(x.EducationLevelId) в качестве фильтра, а затем проверить наличие всех уровней в памяти, используя любой метод, который вы хотите.

Ответ №2:

Используя LinqKit, вы можете создать метод расширения, который будет транслировать в SQL тестовое выражение.

 public static class IQueryableExt { // using LINQKit
    // searchTerms - IEnumerable<TSearch> where all must match for a row
    // testFne(row,searchTerm) - test one of searchTerms against a row
    // r => searchTerms.All(s => testFne(r,s))
    public static Expression<Func<T, bool>> AllAre<T, TSearch>(this IEnumerable<TSearch> searchTerms, Expression<Func<T, TSearch, bool>> testFne) {
        var pred = PredicateBuilder.New<T>();
        foreach (var s in searchTerms)
            pred = pred.And(r => testFne.Invoke(r, s));

        return (Expression<Func<T, bool>>)pred.Expand();
    }

    // searchTerms - IEnumerable<TSearch> where one must match for a row
    // testFne(row,searchTerm) - test one of searchTerms against a row
    // r => searchTerms.All(s => testFne(r,s))
    public static Expression<Func<T, bool>> AnyIs<T, TSearch>(this IEnumerable<TSearch> searchTerms, Expression<Func<T, TSearch, bool>> testFne) {
        var pred = PredicateBuilder.New<T>();
        foreach (var s in searchTerms)
            pred = pred.Or(r => testFne.Invoke(r, s));

        return (Expression<Func<T, bool>>)pred.Expand();
    }
}
  

Предполагая, что вам не нужно, SequenceEquals но только то, что все lst включено, теперь вы можете создать выражение фильтра, используя AllAre :

 var filterExpression = lst.AllAre((SchoolRepresentative sr, long l) => sr.SchoolRepEducationLevels.Select(srel => srel.EducationLevelId).Contains(l));