我有一个使用实体框架核心 1.0.0 的 ASP.NET 核心应用程序。
在特定查询中,我收到"对象引用未设置为对象的实例"异常。
导致异常的查询是:
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 表具有指向 User 的外键,该外键指示它属于哪个用户。还有一个 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 为空):
at lambda_method(Closure , InternalEntityEntry )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleFullyNullableDependentKeyValueFactory
1.TryCreateFromCurrentValues(InternalEntityEntry entry, TKey& key)
at Microsoft.EntityFrameworkCore.Query.Internal.WeakReferenceIdentityMap
1.创建包含键比较器(内部导航,内部实体条目) 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.Include(Object entity) at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(Object entity) at Microsoft.EntityFrameworkCore.Query.Internal.GroupJoinInclude.Include(Object entity) at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.<_GroupJoin>d__26 4.MoveNext()
at System.Linq.Enumerable.<SelectManyIterator>d__163
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.List
1..ctor(IEnumerable 1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 source) at Web.ItemHandlers.GenericItemHandler'1.Get(DataContract dataContract, UserAccount user, ItemDbContext dbc) at Web.Controllers.ItemDataController.Get(String item)
我的查询中有一个非常愚蠢的错误。
s.ItemDataUserRoles.Any( r => r.ItemDataId == s.Id &&
s.User.Roles.Any( t => t.RoleId == r.UserRoleId ) ) ) &&
我正在访问当前项目的 ItemDataUserRoles,但是,我随后将我的项目的 ItemDataUserRoles 列表过滤为仅与我的项目匹配的那些。显然,这是完全多余的检查。然而,这并没有打破它。破坏它的是我做的下一件事是检查这些 ItemDataUserRoles 是否与原始 ItemData 行上的用户匹配,而不是传递的用户。这创建了一个奇怪的SQL查询,给出了错误的结果。