Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query: navigation rewrite fails for queries with navigation inside a subquery inside join inner key selector #8216

Closed
AndriySvyryd opened this issue Apr 18, 2017 · 3 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@AndriySvyryd
Copy link
Member

AndriySvyryd commented Apr 18, 2017

Paste into ComplexNavigationsQueryTestBase:

[ConditionalFact]
public virtual void Query_source_materialization_bug_8216()
{
    AssertQueryScalar<Level1, Level2, int>(
        (l1s, l2s) =>
            from e3 in from e2 in l2s where e2.OneToOne_Required_PK != null select e2.OneToOne_Required_PK
            join e1 in l1s
                on
                (int?)e3.Id
                equals
                (
                    from subQuery2 in l2s
                    join subQuery3 in from e2 in l2s where e2.OneToOne_Required_PK != null select e2.OneToOne_Required_PK
                        on
                        subQuery2 != null ? (int?)subQuery2.Id : null
                        equals
                        subQuery3.Level2_Optional_Id
                        into
                        grouping
                    from subQuery3 in grouping.DefaultIfEmpty()
                    select subQuery3 != null ? (int?)subQuery3.Id : null
                    ).FirstOrDefault()
            select e1.Id);
}

Query model:

from Level2 e2 in DbSet<Level2>
  where [e2].OneToOne_Required_PK != null
  join Level1 e1 in DbSet<Level1>
  on (Nullable<int>) [e2].OneToOne_Required_PK.Id equals 
      (from Level2 subQuery2 in DbSet<Level2>
      join Level3 subQuery3 in 
          from Level2 e2 in DbSet<Level2>
          where [e2].OneToOne_Required_PK != null
          select [e2].OneToOne_Required_PK
      on [subQuery2] != null ? (Nullable<int>) [subQuery2].Id : null equals [subQuery3].Level2_Optional_Id into grouping
      from Level3 subQuery3 in 
          (from Level3 <generated>_1 in [grouping]
          select [<generated>_1]).DefaultIfEmpty()
      select [subQuery3] != null ? (Nullable<int>) [subQuery3].Id : null).FirstOrDefault()
  select [e1].Id

Exception:

System.ArgumentException : Property 'Microsoft.EntityFrameworkCore.Specification.Tests.TestModels.ComplexNavigationsModel.Level3 OneToOne_Required_PK' is not defined for type 'Microsoft.EntityFrameworkCore.Specification.Tests.TestModels.ComplexNavigationsModel.Level3'
at System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property)
at System.Linq.Expressions.Expression.MakeMemberAccess(Expression expression, MemberInfo member)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(402,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.<>c__DisplayClass20_0.<VisitMember>b__1(Expression e)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(792,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.CreateSubqueryForNavigations(Expression outerQuerySourceReferenceExpression, ICollection`1 navigations, Func`2 propertyCreator)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(586,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.RewriteNavigationProperties(IReadOnlyList`1 properties, IQuerySource querySource, Expression expression, Expression declaringExpression, String propertyName, Type propertyType, Func`2 propertyCreator, Func`2 conditionalAccessPropertyCreator)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(395,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.<>c__DisplayClass20_0.<VisitMember>b__0(IReadOnlyList`1 ps, IQuerySource qs)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\EntityQueryModelVisitor.cs(1527,0): at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.BindPropertyExpressionCore[TResult](Expression propertyExpression, IQuerySource querySource, Func`3 propertyBinder)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\EntityQueryModelVisitor.cs(1430,0): at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.BindNavigationPathPropertyExpression[TResult](Expression propertyExpression, Func`3 propertyBinder)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(388,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitMember(MemberExpression node)
at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(234,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitBinary(BinaryExpression node)
at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Remotion.Linq.Clauses.WhereClause.TransformExpressions(Func`2 transformation)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\ExpressionTransformingQueryModelVisitor.cs(69,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ExpressionTransformingQueryModelVisitor`1.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(1266,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.NavigationRewritingQueryModelVisitor.VisitWhereClause(WhereClause whereClause, QueryModel queryModel, Int32 index)
at Remotion.Linq.Clauses.WhereClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(169,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.Rewrite(QueryModel queryModel, QueryModel parentQueryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(223,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitSubQuery(SubQueryExpression expression)
at Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(1305,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.NavigationRewritingQueryModelVisitor.VisitJoinClauseInternal(JoinClause joinClause)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(1297,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.NavigationRewritingQueryModelVisitor.VisitJoinClause(JoinClause joinClause, QueryModel queryModel, GroupJoinClause groupJoinClause)
at Remotion.Linq.Clauses.JoinClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, GroupJoinClause groupJoinClause)
at Remotion.Linq.QueryModelVisitorBase.VisitGroupJoinClause(GroupJoinClause groupJoinClause, QueryModel queryModel, Int32 index)
at Remotion.Linq.Clauses.GroupJoinClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(169,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.Rewrite(QueryModel queryModel, QueryModel parentQueryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(223,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.VisitSubQuery(SubQueryExpression expression)
at Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(1312,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.NavigationRewritingQueryModelVisitor.VisitJoinClauseInternal(JoinClause joinClause)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(1294,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.NavigationRewritingQueryModelVisitor.VisitJoinClause(JoinClause joinClause, QueryModel queryModel, Int32 index)
at Remotion.Linq.Clauses.JoinClause.Accept(IQueryModelVisitor visitor, QueryModel queryModel, Int32 index)
at Remotion.Linq.QueryModelVisitorBase.VisitBodyClauses(ObservableCollection`1 bodyClauses, QueryModel queryModel)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\ExpressionVisitors\Internal\NavigationRewritingExpressionVisitor.cs(169,0): at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.Rewrite(QueryModel queryModel, QueryModel parentQueryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\EntityQueryModelVisitor.cs(320,0): at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.OptimizeQueryModel(QueryModel queryModel, ICollection`1 includeResultOperators, Boolean asyncQuery)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\EntityQueryModelVisitor.cs(201,0): at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
C:\enlistments\Universe\EntityFramework\src\EFCore\Storage\Database.cs(70,0): at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](QueryModel queryModel)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\Internal\QueryCompiler.cs(161,0): at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](Expression query, INodeTypeProvider nodeTypeProvider, IDatabase database, IInterceptingLogger`1 logger, Type contextType)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\Internal\QueryCompiler.cs(99,0): at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_0`1.<Execute>b__0()
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\Internal\CompiledQueryCache.cs(69,0): at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\Internal\CompiledQueryCache.cs(44,0): at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\Internal\QueryCompiler.cs(96,0): at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
C:\enlistments\Universe\EntityFramework\src\EFCore\Query\Internal\EntityQueryProvider.cs(62,0): at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Remotion.Linq.QueryableBase`1.GetEnumerator()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
C:\enlistments\Universe\EntityFramework\src\EFCore.Specification.Tests\ComplexNavigationsQueryTestBase.cs(4296,0): at Microsoft.EntityFrameworkCore.Specification.Tests.ComplexNavigationsQueryTestBase`2.AssertQueryScalar[TItem1,TItem2,TResult](Func`3 efQuery, Func`3 l2oQuery, Boolean verifyOrdered)
C:\enlistments\Universe\EntityFramework\src\EFCore.Specification.Tests\ComplexNavigationsQueryTestBase.cs(4283,0): at Microsoft.EntityFrameworkCore.Specification.Tests.ComplexNavigationsQueryTestBase`2.AssertQueryScalar[TItem1,TItem2,TResult](Func`3 query, Boolean verifyOrdered)
C:\enlistments\Universe\EntityFramework\src\EFCore.Specification.Tests\ComplexNavigationsQueryTestBase.cs(1760,0): at Microsoft.EntityFrameworkCore.Specification.Tests.ComplexNavigationsQueryTestBase`2.Query_source_materialization_bug_8216()
C:\enlistments\Universe\EntityFramework\test\EFCore.InMemory.FunctionalTests\ComplexNavigationsQueryInMemoryTest.cs(27,0): at Microsoft.EntityFrameworkCore.InMemory.FunctionalTests.ComplexNavigationsQueryInMemoryTest.Query_source_materialization_bug_8216()
@ajcvickers ajcvickers modified the milestones: 2.0.0, 2.0.0-preview1 Apr 19, 2017
@AndriySvyryd
Copy link
Member Author

After fixing unskip tests in ComplexNavigationsOwnedQueryTestBase

@maumar
Copy link
Contributor

maumar commented May 17, 2017

This happens because we try to translate navigation in inner key selector of a join clause into a subquery (see #3103 for more info). The translation to subquery that we currently have doesn't work with DIETs, because we assume we can always create a dbset of a type that is the target of the navigation we are rewriting (in this case Level2). However this should only be happening for "naked" navigations. In case of DIETs we have a subquery, so we should be able to translate the navs into normal joins

Simpler example:

from l1 in l1s
join l2 in l2s on l1.Id equals l2s.Select(l => l.Id).OrderBy(l => l).FirstOrDefault()
select new { l1, l2 }

translates initially to:

from Level1 l1 in DbSet<Level1>
join Level2 l2 in 
    from Level1 t in DbSet<Level1>
    where [t].OneToOne_Required_PK != null
    select [t].OneToOne_Required_PK
on [l1].Id equals 
    (from Level1 t in DbSet<Level1>
    where [t].OneToOne_Required_PK != null
    order by [t].OneToOne_Required_PK.Id asc
    select [t].OneToOne_Required_PK.Id).FirstOrDefault()
select new <>f__AnonymousType82<Level1, Level2>(
    [l1], 
    [l2]
)

@maumar maumar changed the title Incorrect type used for query source in a subsubquery Query: navigation rewrite fails for queries with navigation inside a subquery inside join inner key selector May 17, 2017
maumar added a commit that referenced this issue May 17, 2017
…ation inside a subquery inside join inner key selector

Problem was that navigation inside inner key selector of a JoinClause was always being rewritten to subquery (needed for #3103). However, we should only be doing this for "naked" navs - if the nav itself is inside a subquery it can be safely rewritten into a join.

Fix is to "reset" the state indicating whether we are inside join inner key selector every time we visit SubQuery.
maumar added a commit that referenced this issue May 17, 2017
…ation inside a subquery inside join inner key selector

Problem was that navigation inside inner key selector of a JoinClause was always being rewritten to subquery (needed for #3103). However, we should only be doing this for "naked" navs - if the nav itself is inside a subquery it can be safely rewritten into a join.

Fix is to "reset" the state indicating whether we are inside join inner key selector every time we visit SubQuery.
@maumar
Copy link
Contributor

maumar commented May 17, 2017

fixed in 9f75b44

@maumar maumar closed this as completed May 17, 2017
@maumar maumar added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label May 17, 2017
@maumar maumar modified the milestones: 2.0.0-preview2, 2.0.0 May 17, 2017
@ajcvickers ajcvickers modified the milestones: 2.0.0-preview2, 2.0.0 Oct 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

3 participants