diff --git a/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs b/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs index 2f5dec852bc..1a7e7f2ac00 100644 --- a/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs @@ -765,7 +765,8 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp protected override Expression VisitParameter(ParameterExpression parameterExpression) { - if (_allowedParameters.Contains(parameterExpression)) + if (_allowedParameters.Contains(parameterExpression) + || parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal) == true) { return parameterExpression; } diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index cea1656b7f6..529d3213ae0 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -3785,4 +3785,138 @@ public virtual Task Prune_does_not_throw_null_ref(bool async) select l2.Level1_Required_Id).DefaultIfEmpty() from l1 in ss.Set().Where(x => x.Id != ids) select l1); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure(bool async) + { + var prm = 10; + + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping + from l2 in grouping.Where(x => x.Id != prm).DefaultIfEmpty() + select new { Id1 = l1.Id, Id2 = (int?)l2.Id }, + elementSorter: e => (e.Id1, e.Id2), + elementAsserter: (e, a) => + { + Assert.Equal(e.Id1, a.Id1); + Assert.Equal(e.Id2, a.Id2); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupJoin_SelectMany_with_predicate_using_closure(bool async) + { + var prm = 10; + + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping + from l2 in grouping.Where(x => x.Id != prm) + select new { Id1 = l1.Id, Id2 = l2.Id }, + elementSorter: e => (e.Id1, e.Id2), + elementAsserter: (e, a) => + { + Assert.Equal(e.Id1, a.Id1); + Assert.Equal(e.Id2, a.Id2); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested(bool async) + { + var prm1 = 10; + var prm2 = 20; + + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping1 + from l2 in grouping1.Where(x => x.Id != prm1).DefaultIfEmpty() + join l3 in ss.Set() on l2.Id equals l3.Level2_Optional_Id into grouping2 + from l3 in grouping2.Where(x => x.Id != prm2).DefaultIfEmpty() + select new { Id1 = l1.Id, Id2 = (int?)l2.Id, Id3 = (int?)l3.Id }, + elementSorter: e => (e.Id1, e.Id2, e.Id3), + elementAsserter: (e, a) => + { + Assert.Equal(e.Id1, a.Id1); + Assert.Equal(e.Id2, a.Id2); + Assert.Equal(e.Id3, a.Id3); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupJoin_SelectMany_with_predicate_using_closure_nested(bool async) + { + var prm1 = 10; + var prm2 = 20; + + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping1 + from l2 in grouping1.Where(x => x.Id != prm1) + join l3 in ss.Set() on l2.Id equals l3.Level2_Optional_Id into grouping2 + from l3 in grouping2.Where(x => x.Id != prm2) + select new { Id1 = l1.Id, Id2 = l2.Id, Id3 = l3.Id }, + elementSorter: e => (e.Id1, e.Id2, e.Id3), + elementAsserter: (e, a) => + { + Assert.Equal(e.Id1, a.Id1); + Assert.Equal(e.Id2, a.Id2); + Assert.Equal(e.Id3, a.Id3); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested_same_param(bool async) + { + var prm = 10; + + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping1 + from l2 in grouping1.Where(x => x.Id != prm).DefaultIfEmpty() + join l3 in ss.Set() on l2.Id equals l3.Level2_Optional_Id into grouping2 + from l3 in grouping2.Where(x => x.Id != prm).DefaultIfEmpty() + select new { Id1 = l1.Id, Id2 = (int?)l2.Id, Id3 = (int?)l3.Id }, + elementSorter: e => (e.Id1, e.Id2, e.Id3), + elementAsserter: (e, a) => + { + Assert.Equal(e.Id1, a.Id1); + Assert.Equal(e.Id2, a.Id2); + Assert.Equal(e.Id3, a.Id3); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupJoin_SelectMany_with_predicate_using_closure_nested_same_param(bool async) + { + var prm = 10; + + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping1 + from l2 in grouping1.Where(x => x.Id != prm) + join l3 in ss.Set() on l2.Id equals l3.Level2_Optional_Id into grouping2 + from l3 in grouping2.Where(x => x.Id != prm) + select new { Id1 = l1.Id, Id2 = l2.Id, Id3 = l3.Id }, + elementSorter: e => (e.Id1, e.Id2, e.Id3), + elementAsserter: (e, a) => + { + Assert.Equal(e.Id1, a.Id1); + Assert.Equal(e.Id2, a.Id2); + Assert.Equal(e.Id3, a.Id3); + }); + } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 02910614534..3b0ed4d9058 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -4581,6 +4581,136 @@ public override async Task Multiple_required_navigation_with_EF_Property_Include AssertSql(); } + public override async Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure(bool async) + { + await base.GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], [t].[Id] AS [Id2] +FROM [LevelOne] AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[Level1_Optional_Id] + FROM [LevelTwo] AS [l0] + WHERE [l0].[Id] <> @__prm_0 +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_with_predicate_using_closure(bool async) + { + await base.GroupJoin_SelectMany_with_predicate_using_closure(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], [t].[Id] AS [Id2] +FROM [LevelOne] AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[Level1_Optional_Id] + FROM [LevelTwo] AS [l0] + WHERE [l0].[Id] <> @__prm_0 +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested(bool async) + { + await base.GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested(async); + + AssertSql( +""" +@__prm1_0='10' +@__prm2_1='20' + +SELECT [l].[Id] AS [Id1], [t].[Id] AS [Id2], [t0].[Id] AS [Id3] +FROM [LevelOne] AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[Level1_Optional_Id] + FROM [LevelTwo] AS [l0] + WHERE [l0].[Id] <> @__prm1_0 +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l1].[Id], [l1].[Level2_Optional_Id] + FROM [LevelThree] AS [l1] + WHERE [l1].[Id] <> @__prm2_1 +) AS [t0] ON [t].[Id] = [t0].[Level2_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_with_predicate_using_closure_nested(bool async) + { + await base.GroupJoin_SelectMany_with_predicate_using_closure_nested(async); + + AssertSql( +""" +@__prm1_0='10' +@__prm2_1='20' + +SELECT [l].[Id] AS [Id1], [t].[Id] AS [Id2], [t0].[Id] AS [Id3] +FROM [LevelOne] AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[Level1_Optional_Id] + FROM [LevelTwo] AS [l0] + WHERE [l0].[Id] <> @__prm1_0 +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +INNER JOIN ( + SELECT [l1].[Id], [l1].[Level2_Optional_Id] + FROM [LevelThree] AS [l1] + WHERE [l1].[Id] <> @__prm2_1 +) AS [t0] ON [t].[Id] = [t0].[Level2_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested_same_param(bool async) + { + await base.GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested_same_param(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], [t].[Id] AS [Id2], [t0].[Id] AS [Id3] +FROM [LevelOne] AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[Level1_Optional_Id] + FROM [LevelTwo] AS [l0] + WHERE [l0].[Id] <> @__prm_0 +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l1].[Id], [l1].[Level2_Optional_Id] + FROM [LevelThree] AS [l1] + WHERE [l1].[Id] <> @__prm_0 +) AS [t0] ON [t].[Id] = [t0].[Level2_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_with_predicate_using_closure_nested_same_param(bool async) + { + await base.GroupJoin_SelectMany_with_predicate_using_closure_nested_same_param(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], [t].[Id] AS [Id2], [t0].[Id] AS [Id3] +FROM [LevelOne] AS [l] +INNER JOIN ( + SELECT [l0].[Id], [l0].[Level1_Optional_Id] + FROM [LevelTwo] AS [l0] + WHERE [l0].[Id] <> @__prm_0 +) AS [t] ON [l].[Id] = [t].[Level1_Optional_Id] +INNER JOIN ( + SELECT [l1].[Id], [l1].[Level2_Optional_Id] + FROM [LevelThree] AS [l1] + WHERE [l1].[Id] <> @__prm_0 +) AS [t0] ON [t].[Id] = [t0].[Level2_Optional_Id] +"""); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs index 35913c190f3..ba0271686cf 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs @@ -7862,6 +7862,310 @@ public override async Task Multiple_required_navigation_with_EF_Property_Include AssertSql(); } + public override async Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure(bool async) + { + await base.GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END AS [Id2] +FROM [Level1] AS [l] +LEFT JOIN ( + SELECT [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t] ON [l0].[Id] = CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END + WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND (CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END <> @__prm_0 OR CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END IS NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_with_predicate_using_closure(bool async) + { + await base.GroupJoin_SelectMany_with_predicate_using_closure(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END AS [Id2] +FROM [Level1] AS [l] +INNER JOIN ( + SELECT [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t] ON [l0].[Id] = CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END + WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND (CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END <> @__prm_0 OR CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END IS NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested(bool async) + { + await base.GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested(async); + + AssertSql( +""" +@__prm1_0='10' +@__prm2_1='20' + +SELECT [l].[Id] AS [Id1], CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END AS [Id2], CASE + WHEN [t1].[Level2_Required_Id] IS NOT NULL AND [t1].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t1].[Id1] +END AS [Id3] +FROM [Level1] AS [l] +LEFT JOIN ( + SELECT [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t] ON [l0].[Id] = CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END + WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND (CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END <> @__prm1_0 OR CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END IS NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [t3].[Id] AS [Id1], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l2] + LEFT JOIN ( + SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Required_Id], [l3].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l3] + WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t2] ON [l2].[Id] = CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END + LEFT JOIN ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l4] + WHERE [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL + ) AS [t3] ON CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END = CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END + WHERE [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL AND (CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END <> @__prm2_1 OR CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END IS NULL) +) AS [t1] ON CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END = [t1].[Level2_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_with_predicate_using_closure_nested(bool async) + { + await base.GroupJoin_SelectMany_with_predicate_using_closure_nested(async); + + AssertSql( +""" +@__prm1_0='10' +@__prm2_1='20' + +SELECT [l].[Id] AS [Id1], CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END AS [Id2], CASE + WHEN [t1].[Level2_Required_Id] IS NOT NULL AND [t1].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t1].[Id1] +END AS [Id3] +FROM [Level1] AS [l] +INNER JOIN ( + SELECT [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t] ON [l0].[Id] = CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END + WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND (CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END <> @__prm1_0 OR CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END IS NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +INNER JOIN ( + SELECT [t3].[Id] AS [Id1], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l2] + LEFT JOIN ( + SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Required_Id], [l3].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l3] + WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t2] ON [l2].[Id] = CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END + LEFT JOIN ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l4] + WHERE [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL + ) AS [t3] ON CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END = CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END + WHERE [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL AND (CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END <> @__prm2_1 OR CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END IS NULL) +) AS [t1] ON CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END = [t1].[Level2_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested_same_param(bool async) + { + await base.GroupJoin_SelectMany_DefaultIfEmpty_with_predicate_using_closure_nested_same_param(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END AS [Id2], CASE + WHEN [t1].[Level2_Required_Id] IS NOT NULL AND [t1].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t1].[Id1] +END AS [Id3] +FROM [Level1] AS [l] +LEFT JOIN ( + SELECT [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t] ON [l0].[Id] = CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END + WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND (CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END <> @__prm_0 OR CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END IS NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [t3].[Id] AS [Id1], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l2] + LEFT JOIN ( + SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Required_Id], [l3].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l3] + WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t2] ON [l2].[Id] = CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END + LEFT JOIN ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l4] + WHERE [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL + ) AS [t3] ON CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END = CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END + WHERE [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL AND (CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END <> @__prm_0 OR CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END IS NULL) +) AS [t1] ON CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END = [t1].[Level2_Optional_Id] +"""); + } + + public override async Task GroupJoin_SelectMany_with_predicate_using_closure_nested_same_param(bool async) + { + await base.GroupJoin_SelectMany_with_predicate_using_closure_nested_same_param(async); + + AssertSql( +""" +@__prm_0='10' + +SELECT [l].[Id] AS [Id1], CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END AS [Id2], CASE + WHEN [t1].[Level2_Required_Id] IS NOT NULL AND [t1].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t1].[Id1] +END AS [Id3] +FROM [Level1] AS [l] +INNER JOIN ( + SELECT [t].[Id] AS [Id0], [t].[OneToOne_Required_PK_Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t] ON [l0].[Id] = CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END + WHERE [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL AND (CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END <> @__prm_0 OR CASE + WHEN [t].[OneToOne_Required_PK_Date] IS NOT NULL AND [t].[Level1_Required_Id] IS NOT NULL AND [t].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t].[Id] + END IS NULL) +) AS [t0] ON [l].[Id] = [t0].[Level1_Optional_Id] +INNER JOIN ( + SELECT [t3].[Id] AS [Id1], [t3].[Level2_Optional_Id], [t3].[Level2_Required_Id], [t3].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l2] + LEFT JOIN ( + SELECT [l3].[Id], [l3].[OneToOne_Required_PK_Date], [l3].[Level1_Required_Id], [l3].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l3] + WHERE [l3].[OneToOne_Required_PK_Date] IS NOT NULL AND [l3].[Level1_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [t2] ON [l2].[Id] = CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END + LEFT JOIN ( + SELECT [l4].[Id], [l4].[Level2_Optional_Id], [l4].[Level2_Required_Id], [l4].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l4] + WHERE [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL + ) AS [t3] ON CASE + WHEN [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t2].[Id] + END = CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END + WHERE [t2].[OneToOne_Required_PK_Date] IS NOT NULL AND [t2].[Level1_Required_Id] IS NOT NULL AND [t2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL AND (CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END <> @__prm_0 OR CASE + WHEN [t3].[Level2_Required_Id] IS NOT NULL AND [t3].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [t3].[Id] + END IS NULL) +) AS [t1] ON CASE + WHEN [t0].[OneToOne_Required_PK_Date] IS NOT NULL AND [t0].[Level1_Required_Id] IS NOT NULL AND [t0].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [t0].[Id0] +END = [t1].[Level2_Optional_Id] +"""); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }