From 2d8266fb406070be81e8c57123c13cba21e7d6a4 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 6 Jul 2024 11:34:59 +0200 Subject: [PATCH 1/9] Implement `IEnumerable.TakeUpTo` utility It filters out all elements after a certain predicate it satisfied. --- src/Shared/EnumerableExtensions.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Shared/EnumerableExtensions.cs b/src/Shared/EnumerableExtensions.cs index 7e7829c4dcb..ff5a9f33860 100644 --- a/src/Shared/EnumerableExtensions.cs +++ b/src/Shared/EnumerableExtensions.cs @@ -22,6 +22,18 @@ public static IEnumerable Distinct( where T : class => source.Distinct(new DynamicEqualityComparer(comparer)); + public static IEnumerable TakeUpTo(this IEnumerable source, Func predicate) + { + foreach (var item in source) + { + yield return item; + if (predicate(item)) + { + yield break; + } + } + } + private sealed class DynamicEqualityComparer : IEqualityComparer where T : class { From ca0dbac2605fc990a576d3efab20f1ef86e6c707 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 3 Jul 2024 10:10:55 +0200 Subject: [PATCH 2/9] Drop `ELSE NULL` from `CASE` expressions This makes the expression a little simpler and (especially) normalizes the ELSE sub-expression. --- src/EFCore.Relational/Query/SqlNullabilityProcessor.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index 20f898cb8ab..69654029563 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -573,6 +573,11 @@ protected virtual SqlExpression VisitCase(CaseExpression caseExpression, bool al return elseResult ?? _sqlExpressionFactory.Constant(null, caseExpression.Type, caseExpression.TypeMapping); } + if (IsNull(elseResult)) + { + elseResult = null; + } + return caseExpression.Update(operand, whenClauses, elseResult); } From 0bb1b128037f9d55a91b57b39228db1326de5763 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Wed, 3 Jul 2024 10:48:13 +0200 Subject: [PATCH 3/9] Update baselines --- .../AdHocMiscellaneousQuerySqlServerTest.cs | 2 - ...avigationsCollectionsQuerySqlServerTest.cs | 2 - ...CollectionsSharedTypeQuerySqlServerTest.cs | 2 - ...tionsCollectionsSplitQuerySqlServerTest.cs | 3 -- .../Query/GearsOfWarQuerySqlServerTest.cs | 41 ------------------- ...orthwindMiscellaneousQuerySqlServerTest.cs | 1 - .../NorthwindSelectQuerySqlServerTest.cs | 1 - .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 41 ------------------- .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 41 ------------------- ...avigationsCollectionsQuerySqlServerTest.cs | 2 - .../TemporalGearsOfWarQuerySqlServerTest.cs | 41 ------------------- .../Query/GearsOfWarQuerySqliteTest.cs | 41 ------------------- 12 files changed, 218 deletions(-) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs index de969e5374e..16b371a33e7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocMiscellaneousQuerySqlServerTest.cs @@ -1677,7 +1677,6 @@ public override async Task Conditional_expression_with_conditions_does_not_colla """ SELECT CASE WHEN [c0].[Id] IS NOT NULL THEN [c0].[Processed] ^ CAST(1 AS bit) - ELSE NULL END AS [Processing] FROM [Carts] AS [c] LEFT JOIN [Configuration] AS [c0] ON [c].[ConfigurationId] = [c0].[Id] @@ -2398,7 +2397,6 @@ FROM [Customers] AS [c] LEFT JOIN [Countries] AS [c1] ON [c0].[CountryId] = [c1].[Id] WHERE CASE WHEN [c0].[Id] IS NOT NULL THEN [c1].[CountryName] - ELSE NULL END = N'COUNTRY' """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs index fbef3cfbe2e..6ada8222c2e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsQuerySqlServerTest.cs @@ -2990,7 +2990,6 @@ public override async Task Project_collection_and_nested_conditional(bool async) WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END FROM [LevelOne] AS [l] LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[OneToMany_Optional_Inverse2Id] @@ -2998,7 +2997,6 @@ WHERE CASE WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END = N'02' ORDER BY [l].[Id], [l0].[Id] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs index b757fd90033..8e6aa9a6b77 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQuerySqlServerTest.cs @@ -3878,7 +3878,6 @@ public override async Task Project_collection_and_nested_conditional(bool async) WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END FROM [Level1] AS [l] LEFT JOIN ( @@ -3892,7 +3891,6 @@ WHERE CASE WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END = N'02' ORDER BY [l].[Id], [l1].[c] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs index 922133491db..fac384c0bcd 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQuerySqlServerTest.cs @@ -4425,14 +4425,12 @@ public override async Task Project_collection_and_nested_conditional(bool async) WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END FROM [LevelOne] AS [l] WHERE CASE WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END = N'02' ORDER BY [l].[Id] """, @@ -4445,7 +4443,6 @@ WHERE CASE WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END = N'02' ORDER BY [l].[Id], [l2].[Id] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index de530e0f151..745e2560bfd 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -978,7 +978,6 @@ WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE WHEN [g].[LeaderNickname] LIKE N'%us' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END = CAST(1 AS bit) """); } @@ -1010,7 +1009,6 @@ public override async Task Null_propagation_optimization5(bool async) FROM [Gears] AS [g] WHERE CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(LEN([g].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1026,7 +1024,6 @@ public override async Task Null_propagation_optimization6(bool async) FROM [Gears] AS [g] WHERE CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(LEN([g].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1040,7 +1037,6 @@ public override async Task Select_null_propagation_optimization7(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN [g].[LeaderNickname] + [g].[LeaderNickname] - ELSE NULL END FROM [Gears] AS [g] """); @@ -1076,7 +1072,6 @@ public override async Task Select_null_propagation_negative1(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1090,7 +1085,6 @@ public override async Task Select_null_propagation_negative2(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN [g0].[LeaderNickname] - ELSE NULL END FROM [Gears] AS [g] CROSS JOIN [Gears] AS [g0] @@ -1108,7 +1102,6 @@ WHEN [g0].[Nickname] IS NOT NULL AND [g0].[SquadId] IS NOT NULL THEN CASE WHEN [g0].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END AS [Condition] FROM [Gears] AS [g] LEFT JOIN [Gears] AS [g0] ON [g].[HasSoulPatch] = CAST(1 AS bit) @@ -1156,7 +1149,6 @@ public override async Task Select_null_propagation_negative6(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(0 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1170,7 +1162,6 @@ public override async Task Select_null_propagation_negative7(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1184,7 +1175,6 @@ public override async Task Select_null_propagation_negative8(bool async) """ SELECT CASE WHEN [s].[Id] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] @@ -1201,7 +1191,6 @@ public override async Task Select_null_propagation_negative9(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1227,7 +1216,6 @@ public override async Task Select_null_propagation_works_for_multiple_navigation """ SELECT CASE WHEN [c].[Name] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] @@ -3642,7 +3630,6 @@ public override async Task Select_null_conditional_with_inheritance(bool async) """ SELECT CASE WHEN [f].[CommanderName] IS NOT NULL THEN [f].[CommanderName] - ELSE NULL END FROM [Factions] AS [f] """); @@ -3656,7 +3643,6 @@ public override async Task Select_null_conditional_with_inheritance_negative(boo """ SELECT CASE WHEN [f].[CommanderName] IS NOT NULL THEN [f].[Eradicated] - ELSE NULL END FROM [Factions] AS [f] """); @@ -6315,13 +6301,11 @@ public override async Task OrderBy_same_expression_containing_IsNull_correctly_d """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] ORDER BY CASE WHEN CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END @@ -7586,16 +7570,13 @@ public override async Task Join_inner_source_custom_projection_followed_by_filte """ SELECT CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END AS [IsEradicated], [f].[CommanderName], [f].[Name] FROM [LocustLeaders] AS [l] INNER JOIN [Factions] AS [f] ON [l].[Name] = [f].[CommanderName] WHERE CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END = CAST(0 AS bit) OR CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END IS NULL """); } @@ -8654,7 +8635,6 @@ FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END = 1 """); } @@ -8673,7 +8653,6 @@ FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 = 2 """); } @@ -8686,13 +8665,11 @@ public override async Task Projecting_property_converted_to_nullable_with_additi """ SELECT [t].[Note], CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 AS [Value] FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -8706,7 +8683,6 @@ public override async Task Projecting_property_converted_to_nullable_with_condit SELECT CASE WHEN [t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL THEN CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END ELSE -1 END @@ -8723,7 +8699,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT SUBSTRING(CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END, 0 + 1, 3) FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] @@ -8738,13 +8713,11 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT [t].[Note], SUBSTRING([t].[Note], 0 + 1, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END) AS [Function] FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -8757,19 +8730,15 @@ public override async Task Projecting_property_converted_to_nullable_into_elemen """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([g].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -8783,13 +8752,11 @@ public override async Task Projecting_property_converted_to_nullable_into_member """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END AS [Id] FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -8803,19 +8770,15 @@ public override async Task Projecting_property_converted_to_nullable_into_new_ar """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([g].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -8832,10 +8795,8 @@ FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL AND CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[HasSoulPatch] - ELSE NULL END = CAST(0 AS bit) ORDER BY [t].[Note] """); @@ -8869,11 +8830,9 @@ FROM [Tags] AS [t] LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END, [t].[Note] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index 047d9c29e53..49702c16782 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -5873,7 +5873,6 @@ FROM [Orders] AS [o] SELECT TOP(1) [o0].[OrderDate] FROM [Orders] AS [o0] WHERE [c].[CustomerID] = [o0].[CustomerID]) - ELSE NULL END AS [OrderDate] FROM [Customers] AS [c] WHERE [c].[CustomerID] LIKE N'F%' diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index 67f7f8464cd..f9cb0ee3783 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -667,7 +667,6 @@ SELECT CASE WHEN [c].[CustomerID] = N'9' THEN N'09' WHEN [c].[CustomerID] = N'10' THEN N'10' WHEN [c].[CustomerID] = N'11' THEN N'11' - ELSE NULL END FROM [Customers] AS [c] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index bfbb9d79f08..7daaf479286 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -1364,7 +1364,6 @@ WHEN [u].[LeaderNickname] IS NOT NULL THEN CASE WHEN [u].[LeaderNickname] LIKE N'%us' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END = CAST(1 AS bit) """); } @@ -1408,7 +1407,6 @@ FROM [Officers] AS [o] ) AS [u] WHERE CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(LEN([u].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1430,7 +1428,6 @@ FROM [Officers] AS [o] ) AS [u] WHERE CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(LEN([u].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1444,7 +1441,6 @@ public override async Task Select_null_propagation_optimization7(bool async) """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN [u].[LeaderNickname] + [u].[LeaderNickname] - ELSE NULL END FROM ( SELECT [g].[LeaderNickname] @@ -1498,7 +1494,6 @@ public override async Task Select_null_propagation_negative1(bool async) """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([u].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM ( SELECT [g].[Nickname], [g].[LeaderNickname] @@ -1518,7 +1513,6 @@ public override async Task Select_null_propagation_negative2(bool async) """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN [u0].[LeaderNickname] - ELSE NULL END FROM ( SELECT [g].[LeaderNickname] @@ -1548,7 +1542,6 @@ WHEN [u0].[Nickname] IS NOT NULL AND [u0].[SquadId] IS NOT NULL THEN CASE WHEN [u0].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END AS [Condition] FROM ( SELECT [g].[HasSoulPatch] @@ -1632,7 +1625,6 @@ public override async Task Select_null_propagation_negative6(bool async) """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(0 AS bit) - ELSE NULL END FROM ( SELECT [g].[LeaderNickname] @@ -1652,7 +1644,6 @@ public override async Task Select_null_propagation_negative7(bool async) """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE NULL END FROM ( SELECT [g].[LeaderNickname] @@ -1672,7 +1663,6 @@ public override async Task Select_null_propagation_negative8(bool async) """ SELECT CASE WHEN [s].[Id] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] AS [t] LEFT JOIN ( @@ -1695,7 +1685,6 @@ public override async Task Select_null_propagation_negative9(bool async) """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([u].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM ( SELECT [g].[Nickname], [g].[LeaderNickname] @@ -1733,7 +1722,6 @@ public override async Task Select_null_propagation_works_for_multiple_navigation """ SELECT CASE WHEN [c].[Name] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] AS [t] LEFT JOIN ( @@ -4855,7 +4843,6 @@ public override async Task Select_null_conditional_with_inheritance(bool async) """ SELECT CASE WHEN [l].[CommanderName] IS NOT NULL THEN [l].[CommanderName] - ELSE NULL END FROM [LocustHordes] AS [l] """); @@ -4869,7 +4856,6 @@ public override async Task Select_null_conditional_with_inheritance_negative(boo """ SELECT CASE WHEN [l].[CommanderName] IS NOT NULL THEN [l].[Eradicated] - ELSE NULL END FROM [LocustHordes] AS [l] """); @@ -8593,7 +8579,6 @@ public override async Task OrderBy_same_expression_containing_IsNull_correctly_d """ SELECT CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([u].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM ( SELECT [g].[Nickname], [g].[LeaderNickname] @@ -8605,7 +8590,6 @@ FROM [Officers] AS [o] ORDER BY CASE WHEN CASE WHEN [u].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([u].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END @@ -10143,7 +10127,6 @@ public override async Task Join_inner_source_custom_projection_followed_by_filte """ SELECT CASE WHEN [l1].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END AS [IsEradicated], [l1].[CommanderName], [l1].[Name] FROM ( SELECT [l].[Name] @@ -10155,10 +10138,8 @@ FROM [LocustCommanders] AS [l0] INNER JOIN [LocustHordes] AS [l1] ON [u].[Name] = [l1].[CommanderName] WHERE CASE WHEN [l1].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END = CAST(0 AS bit) OR CASE WHEN [l1].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END IS NULL """); } @@ -11413,7 +11394,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END = 1 """); } @@ -11438,7 +11418,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END + 1 = 2 """); } @@ -11451,7 +11430,6 @@ public override async Task Projecting_property_converted_to_nullable_with_additi """ SELECT [t].[Note], CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END + 1 AS [Value] FROM [Tags] AS [t] LEFT JOIN ( @@ -11463,7 +11441,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -11477,7 +11454,6 @@ public override async Task Projecting_property_converted_to_nullable_with_condit SELECT CASE WHEN [t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL THEN CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END ELSE -1 END @@ -11500,7 +11476,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT SUBSTRING(CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END, 0 + 1, 3) FROM [Tags] AS [t] LEFT JOIN ( @@ -11521,7 +11496,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT [t].[Note], SUBSTRING([t].[Note], 0 + 1, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END) AS [Function] FROM [Tags] AS [t] LEFT JOIN ( @@ -11533,7 +11507,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -11546,13 +11519,10 @@ public override async Task Projecting_property_converted_to_nullable_into_elemen """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([u].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END + 1 FROM [Tags] AS [t] LEFT JOIN ( @@ -11564,7 +11534,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -11578,7 +11547,6 @@ public override async Task Projecting_property_converted_to_nullable_into_member """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END AS [Id] FROM [Tags] AS [t] LEFT JOIN ( @@ -11590,7 +11558,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -11604,13 +11571,10 @@ public override async Task Projecting_property_converted_to_nullable_into_new_ar """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([u].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END + 1 FROM [Tags] AS [t] LEFT JOIN ( @@ -11622,7 +11586,6 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -11645,10 +11608,8 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL AND CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[HasSoulPatch] - ELSE NULL END = CAST(0 AS bit) ORDER BY [t].[Note] """); @@ -11694,11 +11655,9 @@ FROM [Officers] AS [o] ) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY CASE WHEN [t].[GearNickName] IS NOT NULL THEN [u].[SquadId] - ELSE NULL END, [t].[Note] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 2421b566d30..855f385b747 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -1188,7 +1188,6 @@ WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE WHEN [g].[LeaderNickname] LIKE N'%us' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END = CAST(1 AS bit) """); } @@ -1226,7 +1225,6 @@ FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] WHERE CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(LEN([g].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1245,7 +1243,6 @@ FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] WHERE CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(LEN([g].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1259,7 +1256,6 @@ public override async Task Select_null_propagation_optimization7(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN [g].[LeaderNickname] + [g].[LeaderNickname] - ELSE NULL END FROM [Gears] AS [g] """); @@ -1295,7 +1291,6 @@ public override async Task Select_null_propagation_negative1(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1309,7 +1304,6 @@ public override async Task Select_null_propagation_negative2(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN [s].[LeaderNickname] - ELSE NULL END FROM [Gears] AS [g] CROSS JOIN ( @@ -1330,7 +1324,6 @@ WHEN [s].[Nickname] IS NOT NULL AND [s].[SquadId] IS NOT NULL THEN CASE WHEN [s].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END AS [Condition] FROM [Gears] AS [g] LEFT JOIN ( @@ -1387,7 +1380,6 @@ public override async Task Select_null_propagation_negative6(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(0 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1401,7 +1393,6 @@ public override async Task Select_null_propagation_negative7(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1415,7 +1406,6 @@ public override async Task Select_null_propagation_negative8(bool async) """ SELECT CASE WHEN [s0].[Id] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] AS [t] LEFT JOIN ( @@ -1435,7 +1425,6 @@ public override async Task Select_null_propagation_negative9(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] """); @@ -1464,7 +1453,6 @@ public override async Task Select_null_propagation_works_for_multiple_navigation """ SELECT CASE WHEN [c].[Name] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] AS [t] LEFT JOIN ( @@ -4147,7 +4135,6 @@ public override async Task Select_null_conditional_with_inheritance(bool async) """ SELECT CASE WHEN [l].[CommanderName] IS NOT NULL THEN [l].[CommanderName] - ELSE NULL END FROM [Factions] AS [f] LEFT JOIN [LocustHordes] AS [l] ON [f].[Id] = [l].[Id] @@ -4163,7 +4150,6 @@ public override async Task Select_null_conditional_with_inheritance_negative(boo """ SELECT CASE WHEN [l].[CommanderName] IS NOT NULL THEN [l].[Eradicated] - ELSE NULL END FROM [Factions] AS [f] LEFT JOIN [LocustHordes] AS [l] ON [f].[Id] = [l].[Id] @@ -7198,13 +7184,11 @@ public override async Task OrderBy_same_expression_containing_IsNull_correctly_d """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] AS [g] ORDER BY CASE WHEN CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END @@ -8613,7 +8597,6 @@ public override async Task Join_inner_source_custom_projection_followed_by_filte """ SELECT CASE WHEN [s].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END AS [IsEradicated], [s].[CommanderName], [s].[Name] FROM [LocustLeaders] AS [l] INNER JOIN ( @@ -8624,10 +8607,8 @@ WHERE [l0].[Id] IS NOT NULL ) AS [s] ON [l].[Name] = [s].[CommanderName] WHERE CASE WHEN [s].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END = CAST(0 AS bit) OR CASE WHEN [s].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END IS NULL """); } @@ -9668,7 +9649,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END = 1 """); } @@ -9690,7 +9670,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END + 1 = 2 """); } @@ -9703,7 +9682,6 @@ public override async Task Projecting_property_converted_to_nullable_with_additi """ SELECT [t].[Note], CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END + 1 AS [Value] FROM [Tags] AS [t] LEFT JOIN ( @@ -9712,7 +9690,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -9726,7 +9703,6 @@ public override async Task Projecting_property_converted_to_nullable_with_condit SELECT CASE WHEN [t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL THEN CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END ELSE -1 END @@ -9746,7 +9722,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT SUBSTRING(CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END, 0 + 1, 3) FROM [Tags] AS [t] LEFT JOIN ( @@ -9764,7 +9739,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT [t].[Note], SUBSTRING([t].[Note], 0 + 1, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END) AS [Function] FROM [Tags] AS [t] LEFT JOIN ( @@ -9773,7 +9747,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -9786,13 +9759,10 @@ public override async Task Projecting_property_converted_to_nullable_into_elemen """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([s].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END + 1 FROM [Tags] AS [t] LEFT JOIN ( @@ -9801,7 +9771,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -9815,7 +9784,6 @@ public override async Task Projecting_property_converted_to_nullable_into_member """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END AS [Id] FROM [Tags] AS [t] LEFT JOIN ( @@ -9824,7 +9792,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -9838,13 +9805,10 @@ public override async Task Projecting_property_converted_to_nullable_into_new_ar """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([s].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END + 1 FROM [Tags] AS [t] LEFT JOIN ( @@ -9853,7 +9817,6 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -9873,10 +9836,8 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL AND CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[HasSoulPatch] - ELSE NULL END = CAST(0 AS bit) ORDER BY [t].[Note] """); @@ -9913,11 +9874,9 @@ FROM [Gears] AS [g] ) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY CASE WHEN [t].[GearNickName] IS NOT NULL THEN [s].[SquadId] - ELSE NULL END, [t].[Note] """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs index 655af6b5543..7115c32d5ee 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalComplexNavigationsCollectionsQuerySqlServerTest.cs @@ -3010,7 +3010,6 @@ public override async Task Project_collection_and_nested_conditional(bool async) WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END FROM [LevelOne] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] LEFT JOIN [LevelTwo] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l0] ON [l].[Id] = [l0].[OneToMany_Optional_Inverse2Id] @@ -3018,7 +3017,6 @@ WHERE CASE WHEN [l].[Id] = 1 THEN N'01' WHEN [l].[Id] = 2 THEN N'02' WHEN [l].[Id] = 3 THEN N'03' - ELSE NULL END = N'02' ORDER BY [l].[Id], [l0].[Id] """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index 5d33396a945..8cc3f649a2d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -754,7 +754,6 @@ WHEN [g0].[Nickname] IS NOT NULL AND [g0].[SquadId] IS NOT NULL THEN CASE WHEN [g0].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END AS [Condition] FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] ON [g].[HasSoulPatch] = CAST(1 AS bit) @@ -809,19 +808,15 @@ public override async Task Projecting_property_converted_to_nullable_into_elemen """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([g].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -1223,7 +1218,6 @@ public override async Task Projecting_property_converted_to_nullable_with_condit SELECT CASE WHEN [t].[Note] <> N'K.I.A.' OR [t].[Note] IS NULL THEN CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END ELSE -1 END @@ -1315,13 +1309,11 @@ public override async Task Projecting_property_converted_to_nullable_with_additi """ SELECT [t].[Note], CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 AS [Value] FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -1604,7 +1596,6 @@ public override async Task Null_propagation_optimization6(bool async) FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] WHERE CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(LEN([g].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -1786,7 +1777,6 @@ public override async Task Select_null_propagation_negative6(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(0 AS bit) - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] """); @@ -2029,7 +2019,6 @@ public override async Task Select_null_propagation_negative7(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] """); @@ -2563,7 +2552,6 @@ public override async Task Select_null_propagation_negative1(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] """); @@ -2577,16 +2565,13 @@ public override async Task Join_inner_source_custom_projection_followed_by_filte """ SELECT CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END AS [IsEradicated], [f].[CommanderName], [f].[Name] FROM [LocustLeaders] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [l] INNER JOIN [Factions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] ON [l].[Name] = [f].[CommanderName] WHERE CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END = CAST(0 AS bit) OR CASE WHEN [f].[Name] = N'Locust' THEN CAST(1 AS bit) - ELSE NULL END IS NULL """); } @@ -2658,7 +2643,6 @@ public override async Task Select_null_propagation_negative9(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] """); @@ -2692,7 +2676,6 @@ ELSE CAST(0 AS bit) LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 = 2 """); } @@ -2811,7 +2794,6 @@ ELSE CAST(0 AS bit) LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END = 1 """); } @@ -3093,19 +3075,15 @@ public override async Task Projecting_property_converted_to_nullable_into_new_ar """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN CAST(LEN([g].[Nickname]) AS int) - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END + 1 FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -3284,7 +3262,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT SUBSTRING(CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END, 0 + 1, 3) FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] @@ -4028,7 +4005,6 @@ public override async Task Null_propagation_optimization5(bool async) FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] WHERE CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(LEN([g].[LeaderNickname]) AS int) - ELSE NULL END = 5 """); } @@ -4913,13 +4889,11 @@ public override async Task Projecting_property_converted_to_nullable_into_member """ SELECT CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END AS [Id] FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY [t].[Note] """); @@ -5163,7 +5137,6 @@ public override async Task Select_null_propagation_optimization7(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN [g].[LeaderNickname] + [g].[LeaderNickname] - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] """); @@ -5272,11 +5245,9 @@ ELSE CAST(0 AS bit) LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL ORDER BY CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END, [t].[Note] """); } @@ -5493,7 +5464,6 @@ public override async Task Select_null_propagation_negative8(bool async) """ SELECT CASE WHEN [s].[Id] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] @@ -5830,7 +5800,6 @@ public override async Task Select_null_propagation_works_for_multiple_navigation """ SELECT CASE WHEN [c].[Name] IS NOT NULL THEN [c].[Name] - ELSE NULL END FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] @@ -6583,13 +6552,11 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT [t].[Note], SUBSTRING([t].[Note], 0 + 1, CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[SquadId] - ELSE NULL END) AS [Function] FROM [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL """); } @@ -7063,7 +7030,6 @@ public override async Task Select_null_conditional_with_inheritance_negative(boo """ SELECT CASE WHEN [f].[CommanderName] IS NOT NULL THEN [f].[Eradicated] - ELSE NULL END FROM [Factions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] """); @@ -7867,7 +7833,6 @@ public override async Task Select_null_conditional_with_inheritance(bool async) """ SELECT CASE WHEN [f].[CommanderName] IS NOT NULL THEN [f].[CommanderName] - ELSE NULL END FROM [Factions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f] """); @@ -8318,13 +8283,11 @@ public override async Task OrderBy_same_expression_containing_IsNull_correctly_d """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ORDER BY CASE WHEN CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN CAST(CAST(LEN([g].[Nickname]) AS int) ^ 5 AS bit) ^ CAST(1 AS bit) - ELSE NULL END IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END @@ -9204,7 +9167,6 @@ public override async Task Select_null_propagation_negative2(bool async) """ SELECT CASE WHEN [g].[LeaderNickname] IS NOT NULL THEN [g0].[LeaderNickname] - ELSE NULL END FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] CROSS JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g0] @@ -9308,10 +9270,8 @@ SELECT [t].[Note] LEFT JOIN [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId] WHERE CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[Nickname] - ELSE NULL END IS NOT NULL AND CASE WHEN [t].[GearNickName] IS NOT NULL THEN [g].[HasSoulPatch] - ELSE NULL END = CAST(0 AS bit) ORDER BY [t].[Note] """); @@ -9400,7 +9360,6 @@ WHEN [g].[LeaderNickname] IS NOT NULL THEN CASE WHEN [g].[LeaderNickname] LIKE N'%us' THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE NULL END = CAST(1 AS bit) """); } diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs index e6bb1577742..cddc6d96f46 100644 --- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs @@ -1065,7 +1065,6 @@ public override async Task Null_propagation_optimization6(bool async) FROM "Gears" AS "g" WHERE CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN length("g"."LeaderNickname") - ELSE NULL END = 5 """); } @@ -1562,7 +1561,6 @@ public override async Task Null_propagation_optimization3(bool async) FROM "Gears" AS "g" WHERE CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN "g"."LeaderNickname" LIKE '%us' - ELSE NULL END """); } @@ -1772,7 +1770,6 @@ public override async Task Select_null_propagation_negative1(bool async) """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN length("g"."Nickname") = 5 - ELSE NULL END FROM "Gears" AS "g" """); @@ -2269,10 +2266,8 @@ public override async Task Projecting_property_converted_to_nullable_into_unary( LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL AND NOT (CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."HasSoulPatch" - ELSE NULL END) ORDER BY "t"."Note" """); @@ -2395,7 +2390,6 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT substr(CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END, 0 + 1, 3) FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" @@ -2738,7 +2732,6 @@ public override async Task Projecting_property_converted_to_nullable_with_additi LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END + 1 = 2 """); } @@ -2876,16 +2869,13 @@ public override async Task Join_inner_source_custom_projection_followed_by_filte """ SELECT CASE WHEN "f"."Name" = 'Locust' THEN 1 - ELSE NULL END AS "IsEradicated", "f"."CommanderName", "f"."Name" FROM "LocustLeaders" AS "l" INNER JOIN "Factions" AS "f" ON "l"."Name" = "f"."CommanderName" WHERE CASE WHEN "f"."Name" = 'Locust' THEN 1 - ELSE NULL END = 0 OR CASE WHEN "f"."Name" = 'Locust' THEN 1 - ELSE NULL END IS NULL """); } @@ -3012,13 +3002,11 @@ public override async Task Projecting_property_converted_to_nullable_into_member """ SELECT CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END AS "Id" FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL ORDER BY "t"."Note" """); @@ -3205,7 +3193,6 @@ public override async Task Select_null_propagation_works_for_multiple_navigation """ SELECT CASE WHEN "c"."Name" IS NOT NULL THEN "c"."Name" - ELSE NULL END FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" @@ -3313,7 +3300,6 @@ public override async Task Select_null_propagation_negative9(bool async) """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN length("g"."Nickname") = 5 - ELSE NULL END FROM "Gears" AS "g" """); @@ -3647,19 +3633,15 @@ public override async Task Projecting_property_converted_to_nullable_into_elemen """ SELECT CASE WHEN "t"."GearNickName" IS NOT NULL THEN length("g"."Nickname") - ELSE NULL END, CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END, CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END + 1 FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL ORDER BY "t"."Note" """); @@ -3846,7 +3828,6 @@ public override async Task Select_null_propagation_negative6(bool async) """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN 0 - ELSE NULL END FROM "Gears" AS "g" """); @@ -4616,7 +4597,6 @@ public override async Task Projecting_property_converted_to_nullable_with_compar LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END = 1 """); } @@ -4856,13 +4836,11 @@ public override async Task Projecting_property_converted_to_nullable_with_functi """ SELECT "t"."Note", substr("t"."Note", 0 + 1, CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END) AS "Function" FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL """); } @@ -4990,19 +4968,15 @@ public override async Task Projecting_property_converted_to_nullable_into_new_ar """ SELECT CASE WHEN "t"."GearNickName" IS NOT NULL THEN length("g"."Nickname") - ELSE NULL END, CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END, CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END + 1 FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL ORDER BY "t"."Note" """); @@ -5289,7 +5263,6 @@ public override async Task Select_null_propagation_negative3(bool async) """ SELECT "g0"."Nickname", CASE WHEN "g0"."Nickname" IS NOT NULL AND "g0"."SquadId" IS NOT NULL THEN "g0"."LeaderNickname" IS NOT NULL - ELSE NULL END AS "Condition" FROM "Gears" AS "g" LEFT JOIN "Gears" AS "g0" ON "g"."HasSoulPatch" @@ -5642,7 +5615,6 @@ public override async Task Select_null_propagation_negative8(bool async) """ SELECT CASE WHEN "s"."Id" IS NOT NULL THEN "c"."Name" - ELSE NULL END FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" @@ -5820,7 +5792,6 @@ public override async Task Select_null_propagation_optimization7(bool async) """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN "g"."LeaderNickname" || "g"."LeaderNickname" - ELSE NULL END FROM "Gears" AS "g" """); @@ -6471,7 +6442,6 @@ public override async Task Select_null_conditional_with_inheritance(bool async) """ SELECT CASE WHEN "f"."CommanderName" IS NOT NULL THEN "f"."CommanderName" - ELSE NULL END FROM "Factions" AS "f" """); @@ -6732,11 +6702,9 @@ public override async Task Projecting_property_converted_to_nullable_and_use_it_ LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL ORDER BY CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END, "t"."Note" """); } @@ -7417,7 +7385,6 @@ public override async Task Select_null_propagation_negative7(bool async) """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN 1 - ELSE NULL END FROM "Gears" AS "g" """); @@ -7552,7 +7519,6 @@ public override async Task Null_propagation_optimization5(bool async) FROM "Gears" AS "g" WHERE CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN length("g"."LeaderNickname") - ELSE NULL END = 5 """); } @@ -8144,13 +8110,11 @@ public override async Task Projecting_property_converted_to_nullable_with_additi """ SELECT "t"."Note", CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END + 1 AS "Value" FROM "Tags" AS "t" LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId" WHERE CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."Nickname" - ELSE NULL END IS NOT NULL """); } @@ -8182,7 +8146,6 @@ public override async Task Select_null_conditional_with_inheritance_negative(boo """ SELECT CASE WHEN "f"."CommanderName" IS NOT NULL THEN "f"."Eradicated" - ELSE NULL END FROM "Factions" AS "f" """); @@ -8226,12 +8189,10 @@ public override async Task OrderBy_same_expression_containing_IsNull_correctly_d """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN length("g"."Nickname") = 5 - ELSE NULL END FROM "Gears" AS "g" ORDER BY CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN length("g"."Nickname") = 5 - ELSE NULL END IS NOT NULL """); } @@ -8635,7 +8596,6 @@ public override async Task Select_null_propagation_negative2(bool async) """ SELECT CASE WHEN "g"."LeaderNickname" IS NOT NULL THEN "g0"."LeaderNickname" - ELSE NULL END FROM "Gears" AS "g" CROSS JOIN "Gears" AS "g0" @@ -8934,7 +8894,6 @@ public override async Task Projecting_property_converted_to_nullable_with_condit SELECT CASE WHEN "t"."Note" <> 'K.I.A.' OR "t"."Note" IS NULL THEN CASE WHEN "t"."GearNickName" IS NOT NULL THEN "g"."SquadId" - ELSE NULL END ELSE -1 END From 2605118dfd1e79318a251fae47b241a91cecd2f8 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 6 Jul 2024 18:27:15 +0200 Subject: [PATCH 4/9] Add tests for `CASE` optimizations --- .../Query/NorthwindSelectQueryCosmosTest.cs | 56 +++++++++++++++++ .../Query/NorthwindSelectQueryTestBase.cs | 46 ++++++++++++++ .../NorthwindSelectQuerySqlServerTest.cs | 62 +++++++++++++++++++ 3 files changed, 164 insertions(+) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index e1a28039882..dff9c2e0838 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -2012,6 +2012,62 @@ public override Task Select_over_10_nested_ternary_condition(bool async) SELECT ((c["CustomerID"] = "1") ? "01" : ((c["CustomerID"] = "2") ? "02" : ((c["CustomerID"] = "3") ? "03" : ((c["CustomerID"] = "4") ? "04" : ((c["CustomerID"] = "5") ? "05" : ((c["CustomerID"] = "6") ? "06" : ((c["CustomerID"] = "7") ? "07" : ((c["CustomerID"] = "8") ? "08" : ((c["CustomerID"] = "9") ? "09" : ((c["CustomerID"] = "10") ? "10" : ((c["CustomerID"] = "11") ? "11" : null))))))))))) AS c FROM root c WHERE (c["Discriminator"] = "Customer") +"""); + }); + + public override Task Select_conditional_drops_false(bool async) + => Fixture.NoSyncTest( + async, async a => + { + await base.Select_conditional_drops_false(a); + + AssertSql( + """ +SELECT (((c["OrderID"] % 2) = 0) ? c["OrderID"] : -(c["OrderID"])) AS c +FROM root c +WHERE (c["Discriminator"] = "Order") +"""); + }); + + public override Task Select_conditional_terminates_at_true(bool async) + => Fixture.NoSyncTest( + async, async a => + { + await base.Select_conditional_terminates_at_true(a); + + AssertSql( + """ +SELECT (((c["OrderID"] % 2) = 0) ? c["OrderID"] : 0) AS c +FROM root c +WHERE (c["Discriminator"] = "Order") +"""); + }); + + public override Task Select_conditional_flatten_nested_results(bool async) + => Fixture.NoSyncTest( + async, async a => + { + await base.Select_conditional_flatten_nested_results(a); + + AssertSql( + """ +SELECT (((c["OrderID"] % 2) = 0) ? (((c["OrderID"] % 5) = 0) ? -(c["OrderID"]) : c["OrderID"]) : c["OrderID"]) AS c +FROM root c +WHERE (c["Discriminator"] = "Order") +"""); + }); + + public override Task Select_conditional_flatten_nested_tests(bool async) + => Fixture.NoSyncTest( + async, async a => + { + await base.Select_conditional_flatten_nested_tests(a); + + AssertSql( + """ +SELECT ((((c["OrderID"] % 2) = 0) ? false : true) ? c["OrderID"] : -(c["OrderID"])) AS c +FROM root c +WHERE (c["Discriminator"] = "Order") """); }); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index ce0c021e3ca..9e60a45a8f1 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -766,6 +766,52 @@ public virtual Task Select_over_10_nested_ternary_condition(bool isAsync) ? "11" : null); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_conditional_drops_false(bool async) + => AssertQueryScalar( + async, + ss => from o in ss.Set() + select o.OrderID % 2 == 0 + ? o.OrderID + : false + ? 0 + : -o.OrderID ); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_conditional_terminates_at_true(bool async) + => AssertQueryScalar( + async, + ss => from o in ss.Set() + select o.OrderID % 2 == 0 + ? o.OrderID + : true + ? 0 + : -o.OrderID ); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_conditional_flatten_nested_results(bool async) + => AssertQueryScalar( + async, + ss => from o in ss.Set() + select o.OrderID % 2 == 0 + ? o.OrderID % 5 == 0 + ? -o.OrderID + : o.OrderID + : o.OrderID); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_conditional_flatten_nested_tests(bool async) + => AssertQueryScalar( + async, + ss => from o in ss.Set() + select (o.OrderID % 2 == 0 ? false : true) + ? o.OrderID + : -o.OrderID); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Projection_in_a_subquery_should_be_liftable(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index f9cb0ee3783..f52cfde033b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -672,6 +672,68 @@ FROM [Customers] AS [c] """); } + public override async Task Select_conditional_drops_false(bool isAsync) + { + await base.Select_conditional_drops_false(isAsync); + + AssertSql( + """ +SELECT CASE + WHEN [o].[OrderID] % 2 = 0 THEN [o].[OrderID] + ELSE -[o].[OrderID] +END +FROM [Orders] AS [o] +"""); + } + + public override async Task Select_conditional_terminates_at_true(bool isAsync) + { + await base.Select_conditional_terminates_at_true(isAsync); + + AssertSql( + """ +SELECT CASE + WHEN [o].[OrderID] % 2 = 0 THEN [o].[OrderID] + ELSE 0 +END +FROM [Orders] AS [o] +"""); + } + + public override async Task Select_conditional_flatten_nested_results(bool isAsync) + { + await base.Select_conditional_flatten_nested_results(isAsync); + + AssertSql( + """ +SELECT CASE + WHEN [o].[OrderID] % 2 = 0 THEN CASE + WHEN [o].[OrderID] % 5 = 0 THEN -[o].[OrderID] + ELSE [o].[OrderID] + END + ELSE [o].[OrderID] +END +FROM [Orders] AS [o] +"""); + } + + public override async Task Select_conditional_flatten_nested_tests(bool isAsync) + { + await base.Select_conditional_flatten_nested_tests(isAsync); + + AssertSql( + """ +SELECT CASE + WHEN CASE + WHEN [o].[OrderID] % 2 = 0 THEN CAST(0 AS bit) + ELSE CAST(1 AS bit) + END = CAST(1 AS bit) THEN [o].[OrderID] + ELSE -[o].[OrderID] +END +FROM [Orders] AS [o] +"""); + } + public override async Task Projection_in_a_subquery_should_be_liftable(bool async) { await base.Projection_in_a_subquery_should_be_liftable(async); From 6c22817e5a143f313dd0337173665f146f4ab4a6 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Fri, 5 Jul 2024 23:43:48 +0200 Subject: [PATCH 5/9] Simplify `CASE` in `SqlExpressionFactory` --- .../Query/ISqlExpressionFactory.cs | 7 +- ...eConverterCompensatingExpressionVisitor.cs | 2 +- ...lExpressionSimplifyingExpressionVisitor.cs | 12 ---- .../Query/SqlExpressionFactory.cs | 67 ++++++++++++++++++- .../Query/SqlNullabilityProcessor.cs | 7 +- ...rchConditionConvertingExpressionVisitor.cs | 2 +- 6 files changed, 74 insertions(+), 23 deletions(-) diff --git a/src/EFCore.Relational/Query/ISqlExpressionFactory.cs b/src/EFCore.Relational/Query/ISqlExpressionFactory.cs index 0bc538aaa1d..5cf4f57d573 100644 --- a/src/EFCore.Relational/Query/ISqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/ISqlExpressionFactory.cs @@ -252,8 +252,13 @@ public interface ISqlExpressionFactory /// An expression to compare with in . /// A list of to compare or evaluate and get result from. /// A value to return if no matches, if any. + /// An optional expression that can be re-used if it matches the new expression. /// An expression representing a CASE statement in a SQL tree. - SqlExpression Case(SqlExpression? operand, IReadOnlyList whenClauses, SqlExpression? elseResult); + SqlExpression Case( + SqlExpression? operand, + IReadOnlyList whenClauses, + SqlExpression? elseResult, + SqlExpression? existingExpr = null); /// /// Creates a new which represent a CASE statement in a SQL tree. diff --git a/src/EFCore.Relational/Query/Internal/RelationalValueConverterCompensatingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalValueConverterCompensatingExpressionVisitor.cs index 025f66d438e..4d3277e86ea 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalValueConverterCompensatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalValueConverterCompensatingExpressionVisitor.cs @@ -72,7 +72,7 @@ private Expression VisitCase(CaseExpression caseExpression) var elseResult = (SqlExpression?)Visit(caseExpression.ElseResult); - return caseExpression.Update(operand, whenClauses, elseResult); + return _sqlExpressionFactory.Case(operand, whenClauses, elseResult, caseExpression); } private Expression VisitSelect(SelectExpression selectExpression) diff --git a/src/EFCore.Relational/Query/Internal/SqlExpressionSimplifyingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/SqlExpressionSimplifyingExpressionVisitor.cs index 731aa047a82..8b7cef3ab73 100644 --- a/src/EFCore.Relational/Query/Internal/SqlExpressionSimplifyingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/SqlExpressionSimplifyingExpressionVisitor.cs @@ -45,18 +45,6 @@ protected override Expression VisitExtension(Expression extensionExpression) return shapedQueryExpression.Update(newQueryExpression, newShaperExpression); } - // Only applies to 'CASE WHEN condition...' not 'CASE operand WHEN...' - if (extensionExpression is CaseExpression - { - Operand: null, ElseResult: CaseExpression { Operand: null } nestedCaseExpression - } caseExpression) - { - return VisitExtension( - _sqlExpressionFactory.Case( - caseExpression.WhenClauses.Union(nestedCaseExpression.WhenClauses).ToList(), - nestedCaseExpression.ElseResult)); - } - if (extensionExpression is SqlBinaryExpression sqlBinaryExpression) { return SimplifySqlBinary(sqlBinaryExpression); diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs index 993803f8c54..1c34ff7cde4 100644 --- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs @@ -686,7 +686,11 @@ public virtual SqlExpression Negate(SqlExpression operand) => MakeUnary(ExpressionType.Negate, operand, operand.Type, operand.TypeMapping)!; /// - public virtual SqlExpression Case(SqlExpression? operand, IReadOnlyList whenClauses, SqlExpression? elseResult) + public virtual SqlExpression Case( + SqlExpression? operand, + IReadOnlyList whenClauses, + SqlExpression? elseResult, + SqlExpression? existingExpr = null) { RelationalTypeMapping? testTypeMapping; if (operand == null) @@ -720,7 +724,66 @@ public virtual SqlExpression Case(SqlExpression? operand, IReadOnlyList !IsSkipped(c)) + .TakeUpTo(IsMatched) + .DistinctBy(c => c.Test) + .ToList(); + + // CASE + // ... + // WHEN TRUE THEN a + // ELSE b + // END + // simplifies to + // CASE + // ... + // ELSE a + // END + if (typeMappedWhenClauses.Count > 0 && IsMatched(typeMappedWhenClauses[^1])) + { + elseResult = typeMappedWhenClauses[^1].Result; + typeMappedWhenClauses.RemoveAt(typeMappedWhenClauses.Count - 1); + } + + // if there are no whenClauses left (e.g. their tests evaluated to false): + // - if there is Else block, return it + // - if there is no Else block, return null + if (typeMappedWhenClauses.Count == 0) + { + return elseResult ?? Constant(null, elseResult?.Type ?? whenClauses[0].Result.Type, resultTypeMapping); + } + + // omit `ELSE NULL` (this makes it easier to compare/reuse expressions) + if (elseResult is SqlConstantExpression { Value: null }) + { + elseResult = null; + } + + return existingExpr is CaseExpression expr + && operand == expr.Operand + && typeMappedWhenClauses.SequenceEqual(expr.WhenClauses) + && elseResult == expr.ElseResult + ? expr + : new CaseExpression(operand, typeMappedWhenClauses, elseResult); + + bool IsFalsy(SqlExpression expr) + => expr is SqlConstantExpression { Value: false or null }; + + bool IsTrue(SqlExpression expr) + => expr is SqlConstantExpression { Value: true }; + + bool IsSkipped(CaseWhenClause clause) + => operand is null && IsFalsy(clause.Test); + + bool IsMatched(CaseWhenClause clause) + => operand is null && IsTrue(clause.Test); } /// diff --git a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs index 69654029563..27927ad1ae7 100644 --- a/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs +++ b/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs @@ -573,12 +573,7 @@ protected virtual SqlExpression VisitCase(CaseExpression caseExpression, bool al return elseResult ?? _sqlExpressionFactory.Constant(null, caseExpression.Type, caseExpression.TypeMapping); } - if (IsNull(elseResult)) - { - elseResult = null; - } - - return caseExpression.Update(operand, whenClauses, elseResult); + return _sqlExpressionFactory.Case(operand, whenClauses, elseResult, caseExpression); } /// diff --git a/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs b/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs index f60f8e35d77..061c79d5822 100644 --- a/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs +++ b/src/EFCore.SqlServer/Query/Internal/SearchConditionConvertingExpressionVisitor.cs @@ -132,7 +132,7 @@ protected override Expression VisitCase(CaseExpression caseExpression) _isSearchCondition = parentSearchCondition; - return ApplyConversion(caseExpression.Update(operand, whenClauses, elseResult), condition: false); + return ApplyConversion(_sqlExpressionFactory.Case(operand, whenClauses, elseResult, caseExpression), condition: false); } /// From 23b67dcb6abd8bde8a89ee9a0927d829519aff9f Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Fri, 5 Jul 2024 23:43:53 +0200 Subject: [PATCH 6/9] Update baselines --- .../Query/GearsOfWarQuerySqlServerTest.cs | 6 ++-- ...orthwindMiscellaneousQuerySqlServerTest.cs | 26 +++++++++----- .../NorthwindSelectQuerySqlServerTest.cs | 6 ++-- .../Query/NullSemanticsQuerySqlServerTest.cs | 36 +++++++------------ .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 6 ++-- .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 6 ++-- .../TemporalGearsOfWarQuerySqlServerTest.cs | 6 ++-- 7 files changed, 39 insertions(+), 53 deletions(-) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 745e2560bfd..e90c186ecd9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -956,10 +956,8 @@ public override async Task Null_propagation_optimization2(bool async) FROM [Gears] AS [g] WHERE CASE WHEN [g].[LeaderNickname] IS NULL THEN NULL - ELSE CASE - WHEN [g].[LeaderNickname] LIKE N'%us' AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [g].[LeaderNickname] LIKE N'%us' AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index 49702c16782..d88fe6eedeb 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -1009,16 +1009,24 @@ ELSE CAST(0 AS bit) } public override async Task OrderBy_ternary_conditions(bool async) - => await base.OrderBy_ternary_conditions(async); + { + await base.OrderBy_ternary_conditions(async); + + AssertSql( + """ +SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] +FROM [Products] AS [p] +ORDER BY CASE + WHEN [p].[UnitsInStock] > CAST(10 AS smallint) THEN CASE + WHEN [p].[ProductID] > 40 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END + WHEN [p].[ProductID] <= 40 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END, [p].[ProductID] +"""); + } - // issue #18774 - // AssertSql( - // @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] - //FROM [Products] AS [p] - //ORDER BY CASE - // WHEN (([p].[UnitsInStock] > CAST(10 AS smallint)) AND ([p].[ProductID] > 40)) OR (([p].[UnitsInStock] <= CAST(10 AS smallint)) AND ([p].[ProductID] <= 40)) - // THEN CAST(1 AS bit) ELSE CAST(0 AS bit) - //END, [p].[ProductID]"); public override async Task OrderBy_any(bool async) { await base.OrderBy_any(async); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index f52cfde033b..cad4913caf6 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -639,10 +639,8 @@ public override async Task Select_conditional_with_null_comparison_in_test(bool """ SELECT CASE WHEN [o].[CustomerID] IS NULL THEN CAST(1 AS bit) - ELSE CASE - WHEN [o].[OrderID] < 100 THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [o].[OrderID] < 100 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END FROM [Orders] AS [o] WHERE [o].[CustomerID] = N'ALFKI' diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index 63b99397333..9b6e3004f16 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -2823,10 +2823,8 @@ ELSE CAST(0 AS bit) END ELSE [e].[BoolC] END <> [e].[BoolB] THEN [e].[BoolA] - ELSE CASE - WHEN ([e].[NullableBoolB] = [e].[NullableBoolC] AND [e].[NullableBoolB] IS NOT NULL AND [e].[NullableBoolC] IS NOT NULL) OR ([e].[NullableBoolB] IS NULL AND [e].[NullableBoolC] IS NULL) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN ([e].[NullableBoolB] = [e].[NullableBoolC] AND [e].[NullableBoolB] IS NOT NULL AND [e].[NullableBoolC] IS NOT NULL) OR ([e].[NullableBoolB] IS NULL AND [e].[NullableBoolC] IS NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """, // @@ -4327,10 +4325,8 @@ WHEN [e].[NullableStringA] IS NULL THEN CASE WHEN ([e].[NullableStringA] <> [e].[NullableStringB] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE CASE - WHEN ([e].[NullableStringA] <> [e].[NullableStringC] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringC] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringC] IS NOT NULL) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN ([e].[NullableStringA] <> [e].[NullableStringC] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringC] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringC] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } @@ -4349,10 +4345,8 @@ WHEN [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL THEN CASE WHEN ([e].[NullableStringA] = [e].[NullableStringB] AND [e].[NullableStringA] IS NOT NULL AND [e].[NullableStringB] IS NOT NULL) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE CASE - WHEN ([e].[NullableStringA] <> [e].[NullableStringB] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN ([e].[NullableStringA] <> [e].[NullableStringB] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } @@ -4370,10 +4364,8 @@ WHERE CASE WHEN ([e].[NullableStringA] = [e].[NullableStringB] AND [e].[NullableStringA] IS NOT NULL AND [e].[NullableStringB] IS NOT NULL) OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE CASE - WHEN ([e].[NullableStringA] <> [e].[NullableStringB] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN ([e].[NullableStringA] <> [e].[NullableStringB] OR [e].[NullableStringA] IS NULL OR [e].[NullableStringB] IS NULL) AND ([e].[NullableStringA] IS NOT NULL OR [e].[NullableStringB] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } @@ -4392,10 +4384,8 @@ WHEN [e].[NullableBoolB] IS NULL THEN CASE WHEN [e].[NullableBoolB] <> [e].[NullableBoolA] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE CASE - WHEN [e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [e].[NullableBoolA] <> [e].[NullableBoolB] OR [e].[NullableBoolB] IS NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } @@ -4415,10 +4405,8 @@ WHEN [e].[NullableBoolC] IS NULL THEN CASE WHEN ([e].[NullableBoolA] <> [e].[NullableBoolC] OR [e].[NullableBoolA] IS NULL OR [e].[NullableBoolC] IS NULL) AND ([e].[NullableBoolA] IS NOT NULL OR [e].[NullableBoolC] IS NOT NULL) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END - ELSE CASE - WHEN ([e].[NullableBoolC] <> [e].[NullableBoolA] OR [e].[NullableBoolC] IS NULL OR [e].[NullableBoolA] IS NULL) AND ([e].[NullableBoolC] IS NOT NULL OR [e].[NullableBoolA] IS NOT NULL) THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN ([e].[NullableBoolC] <> [e].[NullableBoolA] OR [e].[NullableBoolC] IS NULL OR [e].[NullableBoolA] IS NULL) AND ([e].[NullableBoolC] IS NOT NULL OR [e].[NullableBoolA] IS NOT NULL) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index 7daaf479286..7b7ed637938 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -1336,10 +1336,8 @@ FROM [Officers] AS [o] ) AS [u] WHERE CASE WHEN [u].[LeaderNickname] IS NULL THEN NULL - ELSE CASE - WHEN [u].[LeaderNickname] LIKE N'%us' AND [u].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [u].[LeaderNickname] LIKE N'%us' AND [u].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 855f385b747..14fc2bbcda9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -1163,10 +1163,8 @@ FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] WHERE CASE WHEN [g].[LeaderNickname] IS NULL THEN NULL - ELSE CASE - WHEN [g].[LeaderNickname] LIKE N'%us' AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [g].[LeaderNickname] LIKE N'%us' AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index 8cc3f649a2d..e406ddc8439 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -7771,10 +7771,8 @@ public override async Task Null_propagation_optimization2(bool async) FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] WHERE CASE WHEN [g].[LeaderNickname] IS NULL THEN NULL - ELSE CASE - WHEN [g].[LeaderNickname] LIKE N'%us' AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [g].[LeaderNickname] LIKE N'%us' AND [g].[LeaderNickname] IS NOT NULL THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); } From dcf34b8bc1f4dc9997e66e2631e307ab859401b0 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 6 Jul 2024 15:22:40 +0200 Subject: [PATCH 7/9] Flatten nested `CASE` expressions --- .../Query/SqlExpressionFactory.cs | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs index 1c34ff7cde4..4f88b329482 100644 --- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs @@ -718,9 +718,30 @@ public virtual SqlExpression Case( var typeMappedWhenClauses = new List(); foreach (var caseWhenClause in whenClauses) { + var test = caseWhenClause.Test; + + if (operand == null && test is CaseExpression { Operand: null, WhenClauses: [var clause] } testExpr) + { + if (IsTrue(clause.Result) && (testExpr.ElseResult == null || IsFalsy(testExpr.ElseResult))) + { + // WHEN CASE + // WHEN x THEN TRUE + // ELSE FALSE/NULL + // END THEN y + // simplifies to + // WHEN x THEN y + test = clause.Test; + } + else if (IsFalsy(clause.Result) && testExpr.ElseResult != null && IsTrue(testExpr.ElseResult)) + { + // same for the negated results + test = Not(clause.Test); + } + } + typeMappedWhenClauses.Add( new CaseWhenClause( - ApplyTypeMapping(caseWhenClause.Test, testTypeMapping), + ApplyTypeMapping(test, testTypeMapping), ApplyTypeMapping(caseWhenClause.Result, resultTypeMapping))); } @@ -752,12 +773,14 @@ public virtual SqlExpression Case( typeMappedWhenClauses.RemoveAt(typeMappedWhenClauses.Count - 1); } + var nullResult = Constant(null, elseResult?.Type ?? whenClauses[0].Result.Type, resultTypeMapping); + // if there are no whenClauses left (e.g. their tests evaluated to false): // - if there is Else block, return it // - if there is no Else block, return null if (typeMappedWhenClauses.Count == 0) { - return elseResult ?? Constant(null, elseResult?.Type ?? whenClauses[0].Result.Type, resultTypeMapping); + return elseResult ?? nullResult; } // omit `ELSE NULL` (this makes it easier to compare/reuse expressions) @@ -766,6 +789,28 @@ public virtual SqlExpression Case( elseResult = null; } + // CASE + // ... + // WHEN x THEN CASE + // WHEN y THEN a + // ELSE b + // END + // ELSE b + // END + // simplifies to + // CASE + // ... + // WHEN x AND y THEN a + // ELSE b + // END + if (operand == null + && typeMappedWhenClauses[^1].Result is CaseExpression { Operand: null, WhenClauses: [var lastClause] } lastCase + && Equals(elseResult, lastCase.ElseResult)) + { + typeMappedWhenClauses[^1] = new(AndAlso(typeMappedWhenClauses[^1].Test, lastClause.Test), lastClause.Result); + elseResult = lastCase.ElseResult; + } + return existingExpr is CaseExpression expr && operand == expr.Operand && typeMappedWhenClauses.SequenceEqual(expr.WhenClauses) From 1ee4971006583bd72c33345e91437ff10bb482b0 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Sat, 6 Jul 2024 15:22:47 +0200 Subject: [PATCH 8/9] Update baselines --- .../Query/GearsOfWarQuerySqlServerTest.cs | 17 ++++++-------- .../NorthwindSelectQuerySqlServerTest.cs | 10 ++------- .../Query/TPCGearsOfWarQuerySqlServerTest.cs | 17 ++++++-------- .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 22 +++++++------------ .../TemporalGearsOfWarQuerySqlServerTest.cs | 17 ++++++-------- 5 files changed, 31 insertions(+), 52 deletions(-) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index e90c186ecd9..7ca1b124855 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -7686,16 +7686,13 @@ public override async Task Conditional_expression_with_test_being_simplified_to_ SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] WHERE CASE - WHEN [g].[HasSoulPatch] = @__prm_0 THEN CASE - WHEN ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] AS [w] - WHERE [w].[Id] = [g].[SquadId]) = @__prm2_1 AND ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] AS [w] - WHERE [w].[Id] = [g].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [g].[HasSoulPatch] = @__prm_0 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [w].[Id] = [g].[SquadId]) = @__prm2_1 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [w].[Id] = [g].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index cad4913caf6..30732589058 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -705,10 +705,7 @@ public override async Task Select_conditional_flatten_nested_results(bool isAsyn AssertSql( """ SELECT CASE - WHEN [o].[OrderID] % 2 = 0 THEN CASE - WHEN [o].[OrderID] % 5 = 0 THEN -[o].[OrderID] - ELSE [o].[OrderID] - END + WHEN [o].[OrderID] % 2 = 0 AND [o].[OrderID] % 5 = 0 THEN -[o].[OrderID] ELSE [o].[OrderID] END FROM [Orders] AS [o] @@ -722,10 +719,7 @@ public override async Task Select_conditional_flatten_nested_tests(bool isAsync) AssertSql( """ SELECT CASE - WHEN CASE - WHEN [o].[OrderID] % 2 = 0 THEN CAST(0 AS bit) - ELSE CAST(1 AS bit) - END = CAST(1 AS bit) THEN [o].[OrderID] + WHEN [o].[OrderID] % 2 <> 0 THEN [o].[OrderID] ELSE -[o].[OrderID] END FROM [Orders] AS [o] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs index 7b7ed637938..fb3d5eb4945 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs @@ -10261,16 +10261,13 @@ UNION ALL FROM [Officers] AS [o] ) AS [u] WHERE CASE - WHEN [u].[HasSoulPatch] = @__prm_0 THEN CASE - WHEN ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] AS [w] - WHERE [w].[Id] = [u].[SquadId]) = @__prm2_1 AND ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] AS [w] - WHERE [w].[Id] = [u].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [u].[HasSoulPatch] = @__prm_0 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [w].[Id] = [u].[SquadId]) = @__prm2_1 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [w].[Id] = [u].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 14fc2bbcda9..634064306f1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -7808,10 +7808,7 @@ FROM [LocustLeaders] AS [l0] INNER JOIN [LocustCommanders] AS [l1] ON [l0].[Name] = [l1].[Name] ) AS [s] ON [l].[CommanderName] = [s].[Name] WHERE CASE - WHEN [l].[Id] IS NOT NULL THEN CASE - WHEN [s].[Name] IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [l].[Id] IS NOT NULL AND [s].[Name] IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); @@ -8724,16 +8721,13 @@ END AS [Discriminator] FROM [Gears] AS [g] LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] WHERE CASE - WHEN [g].[HasSoulPatch] = @__prm_0 THEN CASE - WHEN ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] AS [w] - WHERE [w].[Id] = [g].[SquadId]) = @__prm2_1 AND ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] AS [w] - WHERE [w].[Id] = [g].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [g].[HasSoulPatch] = @__prm_0 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [w].[Id] = [g].[SquadId]) = @__prm2_1 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] AS [w] + WHERE [w].[Id] = [g].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs index e406ddc8439..a7b9ce28a68 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs @@ -1449,16 +1449,13 @@ public override async Task Conditional_expression_with_test_being_simplified_to_ SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[PeriodEnd], [g].[PeriodStart], [g].[Rank] FROM [Gears] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [g] WHERE CASE - WHEN [g].[HasSoulPatch] = @__prm_0 THEN CASE - WHEN ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] - WHERE [w].[Id] = [g].[SquadId]) = @__prm2_1 AND ( - SELECT TOP(1) [w].[Name] - FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] - WHERE [w].[Id] = [g].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) - ELSE CAST(0 AS bit) - END + WHEN [g].[HasSoulPatch] = @__prm_0 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] + WHERE [w].[Id] = [g].[SquadId]) = @__prm2_1 AND ( + SELECT TOP(1) [w].[Name] + FROM [Weapons] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [w] + WHERE [w].[Id] = [g].[SquadId]) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END = CAST(1 AS bit) """); From e41572310fd5af0ee598e7f6d7afa13599940679 Mon Sep 17 00:00:00 2001 From: Andrea Canciani Date: Fri, 12 Jul 2024 18:36:33 +0200 Subject: [PATCH 9/9] Implement improvements from code review --- .../Query/SqlExpressionFactory.cs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs index 4f88b329482..2630ef75bfd 100644 --- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs +++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs @@ -720,9 +720,10 @@ public virtual SqlExpression Case( { var test = caseWhenClause.Test; - if (operand == null && test is CaseExpression { Operand: null, WhenClauses: [var clause] } testExpr) + if (operand == null && test is CaseExpression { Operand: null, WhenClauses: [var nestedSingleClause] } testExpr) { - if (IsTrue(clause.Result) && (testExpr.ElseResult == null || IsFalsy(testExpr.ElseResult))) + if (nestedSingleClause.Result is SqlConstantExpression { Value: true } + && testExpr.ElseResult is null or SqlConstantExpression { Value: false or null }) { // WHEN CASE // WHEN x THEN TRUE @@ -730,12 +731,13 @@ public virtual SqlExpression Case( // END THEN y // simplifies to // WHEN x THEN y - test = clause.Test; + test = nestedSingleClause.Test; } - else if (IsFalsy(clause.Result) && testExpr.ElseResult != null && IsTrue(testExpr.ElseResult)) + else if (nestedSingleClause.Result is SqlConstantExpression { Value: false or null } + && testExpr.ElseResult is SqlConstantExpression { Value: true }) { // same for the negated results - test = Not(clause.Test); + test = Not(nestedSingleClause.Test); } } @@ -818,17 +820,11 @@ public virtual SqlExpression Case( ? expr : new CaseExpression(operand, typeMappedWhenClauses, elseResult); - bool IsFalsy(SqlExpression expr) - => expr is SqlConstantExpression { Value: false or null }; - - bool IsTrue(SqlExpression expr) - => expr is SqlConstantExpression { Value: true }; - bool IsSkipped(CaseWhenClause clause) - => operand is null && IsFalsy(clause.Test); + => operand is null && clause.Test is SqlConstantExpression { Value: false or null }; bool IsMatched(CaseWhenClause clause) - => operand is null && IsTrue(clause.Test); + => operand is null && clause.Test is SqlConstantExpression { Value: true }; } ///