From 552f70a330f7b93bfc55f17a8b29263b1c0487ae Mon Sep 17 00:00:00 2001 From: Maurycy Markowski Date: Wed, 5 Jul 2017 14:37:34 -0700 Subject: [PATCH] Fix to #8492 - Query: incorrect sql generated for query with owned entities, left join and predicate using inner qsre Problem was that for queries with owned types that were using GroupJoin-SelectMany-DefaultIfEmpty pattern we were not able to find the owned entity type behind the groupjoin subquery qsre. Usually (i.e. in case of navigations) we look for the entity type in the lookup on QueryCompilationContext, but if the groupjoin is created manually then this lookup was not populated with entry for the groupjoin subquery. Fix is to populate the lookup with entry for groupjoin subquery qsre. We do it in nav rewrite, which also populates other entries for owned types. --- .../NavigationRewritingExpressionVisitor.cs | 10 ++++++ ...mplexNavigationsOwnedQuerySqlServerTest.cs | 33 ++++++++++++++++++- .../ComplexNavigationsOwnedQuerySqliteTest.cs | 6 ---- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/EFCore/Query/ExpressionVisitors/Internal/NavigationRewritingExpressionVisitor.cs b/src/EFCore/Query/ExpressionVisitors/Internal/NavigationRewritingExpressionVisitor.cs index c340dbbc9fc..18e54eeb510 100644 --- a/src/EFCore/Query/ExpressionVisitors/Internal/NavigationRewritingExpressionVisitor.cs +++ b/src/EFCore/Query/ExpressionVisitors/Internal/NavigationRewritingExpressionVisitor.cs @@ -1368,6 +1368,7 @@ private class NavigationRewritingQueryModelVisitor : ExpressionTransformingQuery { private readonly CollectionNavigationSubqueryInjector _subqueryInjector; private readonly bool _navigationExpansionSubquery; + private readonly QueryCompilationContext _queryCompilationContext; public AdditionalFromClause AdditionalFromClauseBeingProcessed { get; private set; } @@ -1379,10 +1380,19 @@ public NavigationRewritingQueryModelVisitor( { _subqueryInjector = new CollectionNavigationSubqueryInjector(queryModelVisitor, shouldInject: true); _navigationExpansionSubquery = navigationExpansionSubquery; + _queryCompilationContext = queryModelVisitor.QueryCompilationContext; } public override void VisitAdditionalFromClause(AdditionalFromClause fromClause, QueryModel queryModel, int index) { + // ReSharper disable once PatternAlwaysOfType + if (fromClause.TryGetFlattenedGroupJoinClause()?.JoinClause is JoinClause joinClause + // ReSharper disable once PatternAlwaysOfType + && _queryCompilationContext.FindEntityType(joinClause) is IEntityType entityType) + { + _queryCompilationContext.AddOrUpdateMapping(fromClause, entityType); + } + var oldAdditionalFromClause = AdditionalFromClauseBeingProcessed; AdditionalFromClauseBeingProcessed = fromClause; fromClause.TransformExpressions(TransformingVisitor.Visit); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqlServerTest.cs index d105ebf72c9..ae30cfb4128 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqlServerTest.cs @@ -81,10 +81,41 @@ public override void Nested_group_join_with_take() base.Nested_group_join_with_take(); } - [ConditionalFact(Skip = "issue #8492")] + [ConditionalFact] public override void Explicit_GroupJoin_in_subquery_with_unrelated_projection2() { base.Explicit_GroupJoin_in_subquery_with_unrelated_projection2(); + + AssertSql( + @"SELECT [t1].[Id] +FROM ( + SELECT DISTINCT [l1].* + FROM [Level1] AS [l1] + LEFT JOIN ( + SELECT [t].* + FROM [Level1] AS [t] + WHERE [t].[Id] IS NOT NULL + ) AS [t0] ON [l1].[Id] = [t0].[OneToOne_Required_PK_Level1_Optional_Id] + WHERE ([t0].[OneToOne_Required_PK_Name] <> N'Foo') OR [t0].[OneToOne_Required_PK_Name] IS NULL +) AS [t1]"); + } + + [ConditionalFact] + public override void Result_operator_nav_prop_reference_optional_via_DefaultIfEmpty() + { + base.Result_operator_nav_prop_reference_optional_via_DefaultIfEmpty(); + + AssertSql( + @"SELECT SUM(CASE + WHEN [t0].[Id] IS NULL + THEN 0 ELSE [t0].[OneToOne_Required_PK_Level1_Required_Id] +END) +FROM [Level1] AS [l1] +LEFT JOIN ( + SELECT [t].* + FROM [Level1] AS [t] + WHERE [t].[Id] IS NOT NULL +) AS [t0] ON [l1].[Id] = [t0].[OneToOne_Required_PK_Level1_Optional_Id]"); } private void AssertSql(params string[] expected) diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqliteTest.cs index d9e1f753463..2710a47665d 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexNavigationsOwnedQuerySqliteTest.cs @@ -18,11 +18,5 @@ public override void Nested_group_join_with_take() { base.Nested_group_join_with_take(); } - - [ConditionalFact(Skip = "issue #8492")] - public override void Explicit_GroupJoin_in_subquery_with_unrelated_projection2() - { - base.Explicit_GroupJoin_in_subquery_with_unrelated_projection2(); - } } }