Efcore: Query: Exception when using Include on collection navigation for models also containing owned types

Created on 19 Jul 2017  路  14Comments  路  Source: dotnet/efcore

Describe what is not working as expected.
An exception is thrown when trying to include the related elements on a many to many relationship.

Exception:

ArgumentNullException: Value cannot be null.
 Parameter name: entityType
Microsoft.EntityFrameworkCore.Utilities.Check.NotNull<T>(T value, string parameterName)
Microsoft.EntityFrameworkCore.RelationalMetadataExtensions.Relational(IEntityType entityType)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitEntityQueryable(Type elementType)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.EntityQueryableExpressionVisitor.VisitConstant(ConstantExpression constantExpression)
System.Linq.Expressions.ConstantExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.ReplaceClauseReferences(Expression expression, IQuerySource querySource, bool inProjection)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CompileGroupJoinInnerSequenceExpression(GroupJoinClause groupJoinClause, QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.CompileGroupJoinInnerSequenceExpression(GroupJoinClause groupJoinClause, QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, int index)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, int index)
Remotion.Linq.Clauses.GroupJoinClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, int index)
Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection<IBodyClause> bodyClauses, QueryModel queryModel)
Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitSubQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.LiftSubQuery(IQuerySource querySource, SubQueryExpression subQueryExpression)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.CompileJoinClauseInnerSequenceExpression(JoinClause joinClause, QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitJoinClause(JoinClause joinClause, QueryModel queryModel, int index)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitJoinClause(JoinClause joinClause, QueryModel queryModel, int index)
Remotion.Linq.Clauses.JoinClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, int index)
Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection<IBodyClause> bodyClauses, QueryModel queryModel)
Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitSubQuery(SubQueryExpression expression)
Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.VisitLambda<T>(Expression<T> node)
System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitMethodCall(MethodCallExpression node)
System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
System.Linq.Expressions.BlockExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.ExpressionVisitorBase.VisitLambda<T>(Expression<T> node)
System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitMethodCall(MethodCallExpression node)
System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.RelationalEntityQueryableExpressionVisitor.VisitMember(MemberExpression node)
System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.ReplaceClauseReferences(Expression expression, IQuerySource querySource, bool inProjection)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitSelectClause(SelectClause selectClause, QueryModel queryModel)
Remotion.Linq.Clauses.SelectClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel)
Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.RelationalQueryModelVisitor.VisitQueryModel(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateAsyncQueryExecutor<TResult>(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Storage.Database.CompileAsyncQuery<TResult>(QueryModel queryModel)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQueryCore<TResult>(Expression query, INodeTypeProvider nodeTypeProvider, IDatabase database)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+<>c__DisplayClass24_0.<CompileAsyncQuery>b__0()
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore<TFunc>(object cacheKey, Func<Func<QueryContext, TFunc>> compiler)
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddAsyncQuery<TResult>(object cacheKey, Func<Func<QueryContext, IAsyncEnumerable<TResult>>> compiler)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileAsyncQuery<TResult>(Expression query)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync<TResult>(Expression query)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync<TResult>(Expression expression)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable.System.Collections.Generic.IAsyncEnumerable<TResult>.GetEnumerator()
System.Linq.AsyncEnumerable+<Aggregate_>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
EntityFrameworkVerificationApp.Pages.Movies.Details_Page+<ExecuteAsync>d__0.MoveNext() in Details.cshtml
+
    var movie = await Catalog.Movies.Include(m => m.Cast).ThenInclude(c => c.Artist).Where(m => m.Id == Id).ToListAsync();
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Razor.RazorView+<RenderPageCoreAsync>d__16.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Razor.RazorView+<RenderPageAsync>d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Microsoft.AspNetCore.Mvc.Razor.RazorView+<RenderAsync>d__14.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor+<ExecuteAsync>d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeResultAsync>d__19.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResultFilterAsync>d__24.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeNextResourceFilter>d__22.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeFilterPipelineAsync>d__17.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker+<InvokeAsync>d__15.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Builder.RouterMiddleware+<Invoke>d__4.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware+<Invoke>d__6.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.VisualStudio.Web.BrowserLink.BrowserLinkMiddleware+<ExecuteWithFilter>d__7.MoveNext()
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware+<Invoke>d__7.MoveNext()

Steps to reproduce

Query

var movie = await Catalog.Movies.Include(m => m.Cast).ThenInclude(c => c.Artist).Where(m => m.Id == Id).ToListAsync();

Model

```C#
public class CatalogContext : DbContext
{
public CatalogContext(DbContextOptions options) : base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Movie>(movie =>
    {
        movie
            .HasMany(m => m.Cast)
            .WithOne()
            .HasForeignKey(f => f.MovieId);
        movie.OwnsOne(m => m.Details);
    });

    modelBuilder.Entity<Artist>(artist =>
    {
        artist
            .HasMany(a => a.Movies)
            .WithOne()
            .HasForeignKey(f => f.ArtistId);
        artist.OwnsOne(a => a.PersonalInformation);
    });

    modelBuilder.Entity<MovieArtist>(movieArtist =>
    {
        movieArtist.HasKey(ma => new { ma.MovieId, ma.ArtistId });
    });
}

public DbSet<Movie> Movies { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<MovieArtist> MovieArtists { get; set; }

}

public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public MovieDetails Details { get; set; }
public ICollection Cast { get; set; }
}

public class MovieDetails
{
public DateTimeOffset ReleaseDate { get; set; }
public string Country { get; set; }
public string Language { get; set; }
public string PosterUrl { get; set; }
}

public class MovieArtist
{
public int MovieId { get; set; }
public int ArtistId { get; set; }
public Movie Movie { get; set; }
public Artist Artist { get; set; }
}

public class Artist
{
public int Id { get; set; }
public string ImageUrl { get; set; }
public PersonalInformation PersonalInformation { get; set; }
public ICollection Movies { get; set; }
}

public class PersonalInformation
{
public string GivenName { get; set; }
public string LastName { get; set; }
public DateTimeOffset BirthDate { get; set; }
public string City { get; set; }
public string Country { get; set; }
}


```c#
Console.WriteLine("Hello World!");

Further technical details

EF Core version: Verification build for 2.0.0
Database Provider: SQL
Operating system: Windows Server 2012 R2
IDE: VS 2017 prerel

closed-fixed type-bug

Most helpful comment

@Eilon
Thank you so much for your response!

All 14 comments

Update

After playing a bit more with it, seems that the issue has to do with the MovieDetails owned type. Performing a projection on Movies where you skip the details makes the query succeed.

@maumar Can you investigate this? It probably doesn't meet the bar for 2.0, but it would be good to pin down the conditions needed to hit it and whether or not there are any workarounds.

Update 2

I believe this issue gets triggered whenever you have an owned type and you perform an include for a navigation property on a query.

I was able to trigger the issue with the same model above and just this:

c# var artist = await Catalog.Artists .Include(a => a.Movies) .SingleOrDefaultAsync(a => a.Id == Model.Id);

If I comment out the include the query just succeeds.

@javiercn - Can you run following query and see if it works?
C# var artist = await Catalog.Artists.Include(a => a.Movies).Include(a => a.PersonalInformation).SingleOrDefaultAsync(a => a.Id == Model.Id)

@AndriySvyryd @smitpatel @maumar Can you guys work together to investigate/create a fix. Based on info from @javiercn this may be something we need to fix in 2.0.

/cc @Eilon @divega

Problem happens for queries that include collection navigation that also contains owned type. Problem is that when include compiler modifies query model for collection navigation, it makes a clone of it's part. When there are no owned types it's fine, however for owned types, when we try to determine what entity type corresponds to a given query source, we use a dictionary that maps from query source to a given entity type. When we do the clone, references on the cloned query model are no longer the same, so the entity type cannot be found and hence the exception.

We should be populating the QuerySourceEntityTypeMapping with entries for the cloned query sources.

fixed in 331eab44f9a6246c08b5b0ba8a2a785e76b85447

Congrats, and does that means that 2.0.0 is done?

@weitzhandler - just nearly! We're doing verification and extra testing on the builds (especially integration testing). But aside from super critical fixes, nothing else planned. If you haven't already, try out the bits and let us know what you think!

@Eilon
Thank you so much for your response!

Just hit this, so great that it will be getting fixed in 2.0RTM!

I'm running EF Core 2.1.2 and I'm getting the same error currently. Whenever I use an include it fails.

any fix?

@rrijvy This is fixed in EF Core 2.0.0-preview2, if you are still experiencing it file a new issue

Was this page helpful?
0 / 5 - 0 ratings