Ho un'applicazione ASP.NET Core che utilizza Entity Framework Core 1.0.0.
Su una query specifica ottengo un'eccezione "Riferimento oggetto non impostato su un'istanza di un oggetto".
La query che causa l'eccezione è:
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 );
L'obiettivo della query è restituire un oggetto ItemData che è completamente popolato in cui l'elemento appartiene a un utente o appartiene a qualsiasi ruolo a cui l'utente appartiene. La tabella ItemData ha una chiave esterna per Utente che indica a quale utente appartiene. Esiste anche una tabella ItemDataUserRoles che tiene traccia della relazione many-many tra ItemData e UserRole.
Il resto della query sta filtrando i risultati sulla base di un "id" e "itemName" facoltativi che possono essere passati al metodo.
L'oggetto specifico che sembra essere nullo è s.Item. Se cambio "s.Item.ItemName.ToLower ()" in s.ItemId.ToLower () funziona correttamente.
Tuttavia, il colpevole effettivo sembra essere:
s.ItemDataUserRoles.Any( r => r.ItemDataId == s.Id &&
s.User.Roles.Any( t => t.RoleId == r.UserRoleId ) ) ) &&
Se rimuovo la sezione "s.User.Roles.Any" funziona correttamente (ma non mi dà i risultati che mi servono). Ovviamente, posso fare una query separata per ottenere i dati dei ruoli utente e il controllo incrociato, ma prima di separarli manualmente in quel modo, voglio assicurarmi che non manchi qualcosa di stupido. Ho passato così tanto tempo a cercare di capire cosa sta succedendo che il mio cervello è fritto.
Vale anche la pena notare che se rimuovo il filtro su id e itemName, la query funziona correttamente e sembra che restituisca correttamente gli elementi che appartengono all'utente o a un ruolo a cui l'utente appartiene.
Di seguito è riportata la traccia dello stack (InnerException è null):
at lambda_method(Closure , InternalEntityEntry ) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.SimpleFullyNullableDependentKeyValueFactory
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.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)
C'è stato un errore davvero stupido nella mia domanda.
s.ItemDataUserRoles.Any( r => r.ItemDataId == s.Id &&
s.User.Roles.Any( t => t.RoleId == r.UserRoleId ) ) ) &&
Stavo accedendo a ItemDataUserRoles per l'articolo corrente, tuttavia stavo filtrando l'elenco di ItemDataUserRoles per il mio articolo solo a quelli che corrispondono al mio articolo. Ovviamente, un assegno completamente ridondante. Questo non stava rompendo, comunque. Quello che è stato rotto è la prossima cosa che ho fatto è stato controllare che quei ItemDataUserRoles corrispondano l'utente sulla riga ItemData originale invece che l'utente passato. Questo stava creando una strana query SQL che stava dando risultati errati.