Я немного рефакторинг проекта и вернулся к проблеме, которую я никогда не решал в прошлом. Я пытаюсь выполнить несколько фильтров по запросу базы данных EF Core.
В прошлом я пытался настроить серию операторов Where, которые проверяли, был ли оператор фильтра пустым ИЛИ, сопоставляя фильтр.
Это вернуло исключение nullReferenceException где-то в запросе. Я решил эту проблему, запустив свой запрос без фильтров, а затем применив фильтры к моему списку.
Я вернулся и создал расширение WhereIf и надеялся, что оно, возможно, решит мои проблемы, а также сделает код немного чище, но та же проблема всплывает.
В настоящее время у меня есть четыре фильтра, которые я пытаюсь запустить в запросе, и он отлично проходит исходный фильтр, но если выбран какой-либо из трех других фильтров, запрос имеет исключение nullReferenceException.
Это снова работает, если я получаю список из общего запроса и первого фильтра, а затем впоследствии применяю фильтры к моему списку.
Вот что я хотел бы сделать:
IQueryable<Film> films = _context.Films
.Include(f => f.Media)
.Include(f=> f.Audio)
.Include(f => f.FilmGenres)
.ThenInclude(fg => fg.Genre)
.WhereIf(!string.IsNullOrEmpty(vm.SearchValue), f => f.Name.ToLower().Contains(vm.SearchValue.ToLower()))
.WhereIf(!string.IsNullOrEmpty(vm.MediaFilter), f => f.Media.Name == vm.MediaFilter)
.WhereIf(!string.IsNullOrEmpty(vm.AudioFilter), f => f.Audio.Name == vm.AudioFilter)
.WhereIf(!string.IsNullOrEmpty(vm.GenreFilter), f => f.FilmGenres.Any(fg => fg.Genre != null && fg.Genre.Name == vm.GenreFilter));
Вот метод WhereIf:
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool condition, Expression<Func<TSource, bool>> predicate)
{
// Performs a Where only when the condition is met
if (condition)
{
source = source.Where(predicate);
return source;
}
return source;
}
Фильтр на vm.SearchValue проходит нормально, и когда я перехожу через него, значение IQueryable, как и ожидалось. Как только он попадает в любой из других фильтров, он возвращается с nullReferenceException (когда он, наконец, попадает в ToList () позже). Если я посмотрю на значение source до возврата, оно показывает, что в Result View есть нулевое исключение.
Я пробовал делать каждую строку одну за другой (с фильмом = фильм. Где (...)). Я попытался пропустить WhereIf и просто сделать if и стандартное Where, и все это дает тот же результат.
Только когда я создаю объект List, заполняемый общим запросом данных, а затем фильтрую этот объект List, я заставляю его работать.
Итак, в чем проблема с фильтрацией на IQueryable в EF Core? Это не разрешено, или я что-то не так делаю?
Обновление: все объекты Film имеют объекты Media / Audio / FilmGenre, и все включено. И я проверил, что элементы в источнике IQueryable имеют все эти элементы до оператора Where в методе WhereIf.
Я попытался отделить каждый оператор фильтра отдельно, и это включает в себя пропуск метода WhereIf и использование операторов if.
Кроме того, одновременно можно выбрать только один фильтр (на данный момент). Те, которые не выбраны, приводят к тому, что условие ложно и проблем нет. Он работает только при работе с активным фильтром. Например, я сделаю начальный поиск, который проверяет только vm.SearchValue. Это даст мне список фильмов и опций для фильтрации и сортировки. Затем, когда я выбираю фильтр по аудио или медиа и т. Д., Я получаю проблему.
Вот трассировка стека:
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleNonNullableDependentKeyValueFactory`1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap`1.CreateIncludeKeyComparer(INavigation navigation, InternalEntityEntry entry)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore(Object entity, INavigation navigation)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Int32 currentNavigationIndex, Boolean queryStateManager)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList`1 navigationPath, IReadOnlyList`1 relatedEntitiesLoaders, Boolean queryStateManager)
at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.GroupJoinIncludeContext.Include(Object entity)
at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_GroupJoin>d__26`4.MoveNext()
at System.Linq.Enumerable.<SelectManyIterator>d__165`3.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__15`2.MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source, Int32& length)
at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
Изображения ниже:
- Вот представление результатов источника при прохождении фильтра SearchValue до оператора Where в WhereIf
- Вот оно после того, где утверждение
- Здесь он проходит через AudioFilter - показан предикат.
- Вот источник до оператора Where при выполнении AudioFilter - такой же, как после фильтрации SearchValue
- И, наконец, после выполнения команды Where при выполнении фильтрации аудио
ОБНОВЛЕНИЕ: это было решено. Была еще одна проверка с участием пользователя приложения, которая вызывала оценку на стороне клиента, которая была перемещена, и теперь запрос работает как предполагалось.