Ссылка на основной объект Entity Framework не указывает на экземпляр объекта с вложенным .Any в LINQ

У меня есть приложение ASP.NET Core, использующее Entity Framework Core 1.0.0.

По конкретному запросу я получаю исключение «Ссылка на объект не указывает на экземпляр объекта».

Запрос, вызывающий исключение:

            return mContext.ItemDatas
            .Include( a => a.ItemDataUserRoles )
            .Include( b => b.Item )
            .Include( c => c.User ).ThenInclude( d => d.Roles )
            .Where(
                s =>
                    ( s.User.Id == user.Id ||
                      s.ItemDataUserRoles.Any( r => r.ItemDataId == s.Id &&
                                                      s.User.Roles.Any( t => t.RoleId == r.UserRoleId ) ) ) &&
                    ( string.IsNullOrEmpty( id ) || s.Id == id ) &&
                    ( string.IsNullOrEmpty( itemName ) || s.Item.ItemName.ToLower() == itemName.ToLower() ) &&
                    s.IsActive );

Цель запроса — вернуть полностью заполненный объект ItemData, где элемент принадлежит пользователю или принадлежит любой роли, к которой принадлежит пользователь. Таблица ItemData имеет внешний ключ для пользователя, который указывает, какому пользователю она принадлежит. Существует также таблица ItemDataUserRoles, в которой отслеживается связь «многие-многие» между ItemData и UserRole.

Остальная часть запроса фильтрует результаты на основе необязательных «id» и «itemName», которые можно передать в метод.

Конкретный объект, который кажется нулевым, — это s.Item. Если я изменяю "s.Item.ItemName.ToLower()" на s.ItemId.ToLower(), все работает нормально.

Тем не менее, фактический виновник выглядит следующим образом:

s.ItemDataUserRoles.Any( r => r.ItemDataId == s.Id &&
                                                      s.User.Roles.Any( t => t.RoleId == r.UserRoleId ) ) ) &&

Если я удалю раздел «s.User.Roles.Any», он будет работать нормально (но не даст нужных мне результатов). Очевидно, я могу сделать отдельный запрос, чтобы получить данные о роли пользователя и провести перекрестную проверку, но прежде чем я выделю их вручную, я хочу убедиться, что не упустил ничего глупого. Я потратил так много времени, пытаясь понять, что происходит, что мой мозг поджарился.

Также стоит отметить, что если я удаляю фильтрацию по id и itemName, запрос работает нормально и, кажется, правильно возвращает элементы, принадлежащие пользователю или роли, к которой принадлежит пользователь.

Ниже приведена трассировка стека (InnerException имеет значение null):

at lambda_method(Closure , InternalEntityEntry ) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleFullyNullableDependentKeyValueFactory1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key) at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap1.CreateIncludeKeyComparer (навигация INavigation, запись InternalEntityEntry) в Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.IncludeCore (сущность объекта, навигация INavigation) в Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include (QueryContext queryContext, сущность Object, IReadOnlyList1 navigationPath, IReadOnlyList1 relatedEntitiesLoaders , Int32 currentNavigationIndex, Boolean queryStateManager) в Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.Include(QueryContext queryContext, Object entity, IReadOnlyList1 navigationPath, IReadOnlyList1 relatedEntitiesLoaders, Boolean queryStateManager) в Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(Object entity) в Microsoft .EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(сущность объекта) в Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(сущность объекта) в Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.‹_GroupJoin>d__264.MoveNext() at System.Linq.Enumerable.<SelectManyIterator>d__1633.MoveNext() в System. Linq.Enumerable.WhereSelectEnu merableIterator2.MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.<_TrackEntities>d__152.MoveNext() в Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext() at System.Collections.Generic.List1..ctor(источник IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1) в Web.ItemHandlers.GenericItemHandler`1.Get(DataContract dataContract, пользователь UserAccount, ItemDbContext dbc) в Web.Controllers.ItemDataController .Get(строковый элемент)


person JohnStrom    schedule 11.07.2016    source источник
comment
Вы пробовали проверять нули в своих лямбдах? например : s.User.Roles.Any( t => r.UserRoleId != null && t.RoleId == r.UserRoleId )   -  person Meloviz    schedule 12.07.2016
comment
или попробуйте использовать два отдельных оператора вместо одного длинного оператора....   -  person tCoe    schedule 12.07.2016
comment
Моим первым удачным предположением будет то, что роли будут нулевыми, поэтому, если вы сначала выполните проверку на нуль для этого.   -  person thsorens    schedule 12.07.2016
comment
Согласитесь, что запрос кажется довольно сложным для одного оператора... но... фактическая ошибка связана с s.Item.ItemName... так что это может быть какой-то ItemData, у которого нет Item, или какой-то Item, имеющий null ItemName. .. попробуй на строку, которая доставляет неприятности этому ( string.IsNullOrEmpty( itemName ) || ( (s.Item != null) && (s.Item.ItemName != null) && (s.Item.ItemName.ToLower() == itemName.ToLower()) ) )   -  person David Espino    schedule 12.07.2016


Ответы (1)


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

              s.ItemDataUserRoles.Any( r => r.ItemDataId == s.Id &&
              s.User.Roles.Any( t => t.RoleId == r.UserRoleId ) ) ) &&

Я обращался к ItemDataUserRoles для текущего элемента, однако затем я фильтровал список ItemDataUserRoles для своего элемента, выбирая только те, которые соответствуют моему элементу. Очевидно, совершенно избыточная проверка. Однако это не нарушило его. Что сломало это, так это то, что следующее, что я сделал, — это проверить, соответствуют ли эти ItemDataUserRoles пользователю в исходной строке ItemData, а не переданному пользователю. Это создавало странный запрос SQL, который давал ошибочные результаты.

person JohnStrom    schedule 12.07.2016