diff --git a/EFCore.sln.DotSettings b/EFCore.sln.DotSettings
index b8b7f701254..e8f3d08f6c0 100644
--- a/EFCore.sln.DotSettings
+++ b/EFCore.sln.DotSettings
@@ -356,6 +356,8 @@ The .NET Foundation licenses this file to you under the MIT license.
True
True
True
+ True
+ True
True
True
True
diff --git a/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs b/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs
index b4cfb0938a5..3312572c540 100644
--- a/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs
+++ b/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs
@@ -685,10 +685,37 @@ public virtual SqlExpression Condition(SqlExpression test, SqlExpression ifTrue,
{
var typeMapping = ExpressionExtensions.InferTypeMapping(ifTrue, ifFalse);
- return new SqlConditionalExpression(
- ApplyTypeMapping(test, _boolTypeMapping),
- ApplyTypeMapping(ifTrue, typeMapping),
- ApplyTypeMapping(ifFalse, typeMapping));
+ test = ApplyTypeMapping(test, _boolTypeMapping);
+ ifTrue = ApplyTypeMapping(ifTrue, typeMapping);
+ ifFalse = ApplyTypeMapping(ifFalse, typeMapping);
+
+ // Simplify:
+ // a == b ? b : a -> a
+ // a != b ? a : b -> a
+ if (test is SqlBinaryExpression
+ {
+ OperatorType: ExpressionType.Equal or ExpressionType.NotEqual,
+ Left: var left,
+ Right: var right
+ } binary)
+ {
+ // Reverse ifEqual/ifNotEqual for ExpressionType.NotEqual for easier reasoning below
+ var (ifEqual, ifNotEqual) = binary.OperatorType is ExpressionType.Equal ? (ifTrue, ifFalse) : (ifFalse, ifTrue);
+
+ // a == b ? b : a -> a
+ if (left.Equals(ifNotEqual) && right.Equals(ifEqual))
+ {
+ return left;
+ }
+
+ // b == a ? b : a -> a
+ if (right.Equals(ifNotEqual) && left.Equals(ifEqual))
+ {
+ return right;
+ }
+ }
+
+ return new SqlConditionalExpression(test, ifTrue, ifFalse);
}
///
diff --git a/src/EFCore.Relational/Query/SqlExpressionFactory.cs b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
index 064e97cbe74..088ee857231 100644
--- a/src/EFCore.Relational/Query/SqlExpressionFactory.cs
+++ b/src/EFCore.Relational/Query/SqlExpressionFactory.cs
@@ -825,6 +825,58 @@ public virtual SqlExpression Case(
elseResult = lastCase.ElseResult;
}
+ // Simplify:
+ // a == b ? b : a -> a
+ // a != b ? a : b -> a
+ // And lift:
+ // a == b ? null : a -> NULLIF(a, b)
+ // a != b ? a : null -> NULLIF(a, b)
+ if (operand is null
+ && typeMappedWhenClauses is
+ [
+ {
+ Test: SqlBinaryExpression
+ {
+ OperatorType: ExpressionType.Equal or ExpressionType.NotEqual,
+ Left: var left,
+ Right: var right
+ } binary,
+ Result: var result
+ }
+ ])
+ {
+ // Reverse ifEqual/ifNotEqual for ExpressionType.NotEqual for easier reasoning below
+ var (ifEqual, ifNotEqual) = binary.OperatorType is ExpressionType.Equal
+ ? (result, elseResult ?? Constant(null, result.Type, result.TypeMapping))
+ : (elseResult ?? Constant(null, result.Type, result.TypeMapping), result);
+
+ if (left.Equals(ifNotEqual))
+ {
+ switch (ifEqual)
+ {
+ // a == b ? b : a -> a
+ case var _ when ifEqual.Equals(right):
+ return left;
+ // a == b ? null : a -> NULLIF(a, b)
+ case SqlConstantExpression { Value: null }:
+ return Function("NULLIF", [left, right], nullable: true, [false, false], left.Type, left.TypeMapping);
+ }
+ }
+
+ if (right.Equals(ifNotEqual))
+ {
+ switch (ifEqual)
+ {
+ // b == a ? b : a -> a
+ case var _ when ifEqual.Equals(left):
+ return right;
+ // b == a ? null : a -> NULLIF(a, b)
+ case SqlConstantExpression { Value: null }:
+ return Function("NULLIF", [right, left], nullable: true, [false, false], right.Type, right.TypeMapping);
+ }
+ }
+ }
+
return existingExpression is CaseExpression expr
&& operand == expr.Operand
&& typeMappedWhenClauses.SequenceEqual(expr.WhenClauses)
diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/Translations/OperatorTranslationsCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/Translations/OperatorTranslationsCosmosTest.cs
index ab39e7c5b37..967ee86c1c4 100644
--- a/test/EFCore.Cosmos.FunctionalTests/Query/Translations/OperatorTranslationsCosmosTest.cs
+++ b/test/EFCore.Cosmos.FunctionalTests/Query/Translations/OperatorTranslationsCosmosTest.cs
@@ -14,6 +14,94 @@ public OperatorTranslationsCosmosTest(BasicTypesQueryCosmosFixture fixture, ITes
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+ #region Conditional
+
+ public override Task Conditional_simplifiable_equality(bool async)
+ => Fixture.NoSyncTest(
+ async, async a =>
+ {
+ await base.Conditional_simplifiable_equality(a);
+
+ AssertSql(
+ """
+SELECT VALUE c
+FROM root c
+WHERE (c["Int"] > 1)
+""");
+ });
+
+ public override Task Conditional_simplifiable_inequality(bool async)
+ => Fixture.NoSyncTest(
+ async, async a =>
+ {
+ await base.Conditional_simplifiable_inequality(a);
+
+ AssertSql(
+ """
+SELECT VALUE c
+FROM root c
+WHERE (c["Int"] > 1)
+""");
+ });
+
+ public override Task Conditional_uncoalesce_with_equality_left(bool async)
+ => Fixture.NoSyncTest(
+ async, async a =>
+ {
+ await base.Conditional_uncoalesce_with_equality_left(a);
+
+ AssertSql(
+ """
+SELECT VALUE c
+FROM root c
+WHERE (((c["Int"] = 9) ? null : c["Int"]) > 1)
+""");
+ });
+
+ public override Task Conditional_uncoalesce_with_equality_right(bool async)
+ => Fixture.NoSyncTest(
+ async, async a =>
+ {
+ await base.Conditional_uncoalesce_with_equality_right(a);
+
+ AssertSql(
+ """
+SELECT VALUE c
+FROM root c
+WHERE (((9 = c["Int"]) ? null : c["Int"]) > 1)
+""");
+ });
+
+ public override Task Conditional_uncoalesce_with_unequality_left(bool async)
+ => Fixture.NoSyncTest(
+ async, async a =>
+ {
+ await base.Conditional_uncoalesce_with_unequality_left(a);
+
+ AssertSql(
+ """
+SELECT VALUE c
+FROM root c
+WHERE (((c["Int"] != 9) ? c["Int"] : null) > 1)
+""");
+ });
+
+ public override Task Conditional_uncoalesce_with_inequality_right(bool async)
+ => Fixture.NoSyncTest(
+ async, async a =>
+ {
+ await base.Conditional_uncoalesce_with_inequality_right(a);
+
+ AssertSql(
+ """
+SELECT VALUE c
+FROM root c
+WHERE (((9 != c["Int"]) ? c["Int"] : null) > 1)
+""");
+ });
+
+ #endregion Conditional
+
#region Bitwise
public override Task Bitwise_or(bool async)
diff --git a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs
index 6ce93abfd78..53e80173c62 100644
--- a/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Query/NullSemanticsQueryTestBase.cs
@@ -753,7 +753,7 @@ public virtual Task Where_equal_with_conditional(bool async)
ss => ss.Set().Where(
e => (e.NullableStringA == e.NullableStringB
? e.NullableStringA
- : e.NullableStringB)
+ : e.NullableStringC)
== e.NullableStringC).Select(e => e.Id));
[ConditionalTheory]
@@ -765,7 +765,7 @@ public virtual Task Where_not_equal_with_conditional(bool async)
e => e.NullableStringC
!= (e.NullableStringA == e.NullableStringB
? e.NullableStringA
- : e.NullableStringB)).Select(e => e.Id));
+ : e.NullableStringC)).Select(e => e.Id));
[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
diff --git a/test/EFCore.Specification.Tests/Query/Translations/OperatorTranslationsTestBase.cs b/test/EFCore.Specification.Tests/Query/Translations/OperatorTranslationsTestBase.cs
index a1f58662859..4ccbe805f4d 100644
--- a/test/EFCore.Specification.Tests/Query/Translations/OperatorTranslationsTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/Translations/OperatorTranslationsTestBase.cs
@@ -8,6 +8,58 @@ namespace Microsoft.EntityFrameworkCore.Query.Translations;
public abstract class OperatorTranslationsTestBase(TFixture fixture) : QueryTestBase(fixture)
where TFixture : BasicTypesQueryFixtureBase, new()
{
+ // See also operators precedence tests in OperatorsQueryTestBase
+
+ #region Conditional
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Conditional_simplifiable_equality(bool async)
+ => AssertQuery(
+ async,
+ // ReSharper disable once MergeConditionalExpression
+ cs => cs.Set().Where(x => (x.Int == 9 ? 9 : x.Int) > 1));
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Conditional_simplifiable_inequality(bool async)
+ => AssertQuery(
+ async,
+ // ReSharper disable once MergeConditionalExpression
+ cs => cs.Set().Where(x => (x.Int != 8 ? x.Int : 8) > 1));
+
+ // In relational providers, x == a ? null : x ("un-coalescing conditional") is translated to SQL NULLIF
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Conditional_uncoalesce_with_equality_left(bool async)
+ => AssertQuery(
+ async,
+ cs => cs.Set().Where(x => (x.Int == 9 ? null : x.Int) > 1));
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Conditional_uncoalesce_with_equality_right(bool async)
+ => AssertQuery(
+ async,
+ cs => cs.Set().Where(x => (9 == x.Int ? null : x.Int) > 1));
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Conditional_uncoalesce_with_unequality_left(bool async)
+ => AssertQuery(
+ async,
+ cs => cs.Set().Where(x => (x.Int != 9 ? x.Int : null) > 1));
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Conditional_uncoalesce_with_inequality_right(bool async)
+ => AssertQuery(
+ async,
+ cs => cs.Set().Where(x => (9 != x.Int ? x.Int : null) > 1));
+
+ #endregion Conditional
+
#region Bitwise
#pragma warning disable CS0675 // Bitwise-or operator used on a sign-extended operand
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
index d12c45997f3..508437851dc 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs
@@ -855,9 +855,7 @@ public override async Task Select_null_propagation_works_for_multiple_navigation
AssertSql(
"""
-SELECT CASE
- WHEN [c].[Name] IS NOT NULL THEN [c].[Name]
-END
+SELECT [c].[Name]
FROM [Tags] AS [t]
LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId]
LEFT JOIN [Tags] AS [t0] ON ([g].[Nickname] = [t0].[GearNickName] OR ([g].[Nickname] IS NULL AND [t0].[GearNickName] IS NULL)) AND ([g].[SquadId] = [t0].[GearSquadId] OR ([g].[SquadId] IS NULL AND [t0].[GearSquadId] IS NULL))
@@ -1981,10 +1979,7 @@ public override async Task Optional_navigation_type_compensation_works_with_pred
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note]
FROM [Tags] AS [t]
LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId]
-WHERE CASE
- WHEN [g].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit)
- ELSE [g].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [g].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -1997,10 +1992,7 @@ public override async Task Optional_navigation_type_compensation_works_with_pred
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note]
FROM [Tags] AS [t]
LEFT JOIN [Gears] AS [g] ON [t].[GearNickName] = [g].[Nickname] AND [t].[GearSquadId] = [g].[SquadId]
-WHERE CASE
- WHEN [g].[HasSoulPatch] = CAST(0 AS bit) THEN CAST(0 AS bit)
- ELSE [g].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [g].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -3057,9 +3049,7 @@ public override async Task Select_null_conditional_with_inheritance(bool async)
AssertSql(
"""
-SELECT CASE
- WHEN [f].[CommanderName] IS NOT NULL THEN [f].[CommanderName]
-END
+SELECT [f].[CommanderName]
FROM [Factions] AS [f]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs
index d1cced85865..43d006ca396 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindFunctionsQuerySqlServer160Test.cs
@@ -21,6 +21,18 @@ public NorthwindFunctionsQuerySqlServer160Test(Fixture160 fixture, ITestOutputHe
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
+ public override async Task Client_evaluation_of_uncorrelated_method_call(bool async)
+ {
+ await base.Client_evaluation_of_uncorrelated_method_call(async);
+
+ AssertSql(
+ """
+SELECT [o].[OrderID], [o].[ProductID], [o].[Discount], [o].[Quantity], [o].[UnitPrice]
+FROM [Order Details] AS [o]
+WHERE [o].[UnitPrice] < 7.0 AND 10 < [o].[ProductID]
+""");
+ }
+
public override async Task Sum_over_round_works_correctly_in_projection(bool async)
{
await base.Sum_over_round_works_correctly_in_projection(async);
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs
index d771cc25f85..77494e237a0 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs
@@ -2207,10 +2207,10 @@ SELECT [e].[Id]
FROM [Entities1] AS [e]
WHERE CASE
WHEN [e].[NullableStringA] = [e].[NullableStringB] OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA]
- ELSE [e].[NullableStringB]
+ ELSE [e].[NullableStringC]
END = [e].[NullableStringC] OR (CASE
WHEN [e].[NullableStringA] = [e].[NullableStringB] OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA]
- ELSE [e].[NullableStringB]
+ ELSE [e].[NullableStringC]
END IS NULL AND [e].[NullableStringC] IS NULL)
""");
}
@@ -2225,13 +2225,13 @@ SELECT [e].[Id]
FROM [Entities1] AS [e]
WHERE ([e].[NullableStringC] <> CASE
WHEN [e].[NullableStringA] = [e].[NullableStringB] OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA]
- ELSE [e].[NullableStringB]
+ ELSE [e].[NullableStringC]
END OR [e].[NullableStringC] IS NULL OR CASE
WHEN [e].[NullableStringA] = [e].[NullableStringB] OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA]
- ELSE [e].[NullableStringB]
+ ELSE [e].[NullableStringC]
END IS NULL) AND ([e].[NullableStringC] IS NOT NULL OR CASE
WHEN [e].[NullableStringA] = [e].[NullableStringB] OR ([e].[NullableStringA] IS NULL AND [e].[NullableStringB] IS NULL) THEN [e].[NullableStringA]
- ELSE [e].[NullableStringB]
+ ELSE [e].[NullableStringC]
END IS NOT NULL)
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
index 182be105b6d..18aca22ea4c 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPCGearsOfWarQuerySqlServerTest.cs
@@ -1157,9 +1157,7 @@ public override async Task Select_null_propagation_works_for_multiple_navigation
AssertSql(
"""
-SELECT CASE
- WHEN [c].[Name] IS NOT NULL THEN [c].[Name]
-END
+SELECT [c].[Name]
FROM [Tags] AS [t]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId]
@@ -2741,10 +2739,7 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId], [o].[HasSoulPatch]
FROM [Officers] AS [o]
) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId]
-WHERE CASE
- WHEN [u].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit)
- ELSE [u].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [u].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -2763,10 +2758,7 @@ UNION ALL
SELECT [o].[Nickname], [o].[SquadId], [o].[HasSoulPatch]
FROM [Officers] AS [o]
) AS [u] ON [t].[GearNickName] = [u].[Nickname] AND [t].[GearSquadId] = [u].[SquadId]
-WHERE CASE
- WHEN [u].[HasSoulPatch] = CAST(0 AS bit) THEN CAST(0 AS bit)
- ELSE [u].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [u].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -4066,9 +4058,7 @@ public override async Task Select_null_conditional_with_inheritance(bool async)
AssertSql(
"""
-SELECT CASE
- WHEN [l].[CommanderName] IS NOT NULL THEN [l].[CommanderName]
-END
+SELECT [l].[CommanderName]
FROM [LocustHordes] AS [l]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
index 62be1d75c6a..070adfd5e7c 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs
@@ -1035,9 +1035,7 @@ public override async Task Select_null_propagation_works_for_multiple_navigation
AssertSql(
"""
-SELECT CASE
- WHEN [c].[Name] IS NOT NULL THEN [c].[Name]
-END
+SELECT [c].[Name]
FROM [Tags] AS [t]
LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId]
@@ -2363,10 +2361,7 @@ LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[HasSoulPatch]
FROM [Gears] AS [g]
) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId]
-WHERE CASE
- WHEN [s].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit)
- ELSE [s].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [s].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -2382,10 +2377,7 @@ LEFT JOIN (
SELECT [g].[Nickname], [g].[SquadId], [g].[HasSoulPatch]
FROM [Gears] AS [g]
) AS [s] ON [t].[GearNickName] = [s].[Nickname] AND [t].[GearSquadId] = [s].[SquadId]
-WHERE CASE
- WHEN [s].[HasSoulPatch] = CAST(0 AS bit) THEN CAST(0 AS bit)
- ELSE [s].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [s].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -3505,9 +3497,7 @@ public override async Task Select_null_conditional_with_inheritance(bool async)
AssertSql(
"""
-SELECT CASE
- WHEN [l].[CommanderName] IS NOT NULL THEN [l].[CommanderName]
-END
+SELECT [l].[CommanderName]
FROM [Factions] AS [f]
LEFT JOIN [LocustHordes] AS [l] ON [f].[Id] = [l].[Id]
WHERE [l].[Id] IS NOT NULL
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
index 727f120e502..f1948bf9ea3 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/TemporalGearsOfWarQuerySqlServerTest.cs
@@ -724,10 +724,7 @@ public override async Task Optional_navigation_type_compensation_works_with_pred
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart]
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 [g].[HasSoulPatch] = CAST(1 AS bit) THEN CAST(1 AS bit)
- ELSE [g].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [g].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -1570,10 +1567,7 @@ public override async Task Optional_navigation_type_compensation_works_with_pred
SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[IssueDate], [t].[Note], [t].[PeriodEnd], [t].[PeriodStart]
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 [g].[HasSoulPatch] = CAST(0 AS bit) THEN CAST(0 AS bit)
- ELSE [g].[HasSoulPatch]
-END = CAST(0 AS bit)
+WHERE [g].[HasSoulPatch] = CAST(0 AS bit)
""");
}
@@ -5059,9 +5053,7 @@ public override async Task Select_null_propagation_works_for_multiple_navigation
AssertSql(
"""
-SELECT CASE
- WHEN [c].[Name] IS NOT NULL THEN [c].[Name]
-END
+SELECT [c].[Name]
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]
LEFT JOIN [Tags] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [t0] ON ([g].[Nickname] = [t0].[GearNickName] OR ([g].[Nickname] IS NULL AND [t0].[GearNickName] IS NULL)) AND ([g].[SquadId] = [t0].[GearSquadId] OR ([g].[SquadId] IS NULL AND [t0].[GearSquadId] IS NULL))
@@ -6988,9 +6980,7 @@ public override async Task Select_null_conditional_with_inheritance(bool async)
AssertSql(
"""
-SELECT CASE
- WHEN [f].[CommanderName] IS NOT NULL THEN [f].[CommanderName]
-END
+SELECT [f].[CommanderName]
FROM [Factions] FOR SYSTEM_TIME AS OF '2010-01-01T00:00:00.0000000' AS [f]
""");
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Translations/OperatorTranslationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Translations/OperatorTranslationsSqlServerTest.cs
index 8c28b93ed39..c1343173259 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/Translations/OperatorTranslationsSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/Translations/OperatorTranslationsSqlServerTest.cs
@@ -12,6 +12,82 @@ public OperatorTranslationsSqlServerTest(BasicTypesQuerySqlServerFixture fixture
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+ #region Conditional
+
+ public override async Task Conditional_simplifiable_equality(bool async)
+ {
+ await base.Conditional_simplifiable_equality(async);
+
+ AssertSql(
+ """
+SELECT [n].[Id], [n].[Bool], [n].[Byte], [n].[ByteArray], [n].[DateOnly], [n].[DateTime], [n].[DateTimeOffset], [n].[Decimal], [n].[Double], [n].[Enum], [n].[FlagsEnum], [n].[Float], [n].[Guid], [n].[Int], [n].[Long], [n].[Short], [n].[String], [n].[TimeOnly], [n].[TimeSpan]
+FROM [NullableBasicTypesEntities] AS [n]
+WHERE [n].[Int] > 1
+""");
+ }
+
+ public override async Task Conditional_simplifiable_inequality(bool async)
+ {
+ await base.Conditional_simplifiable_inequality(async);
+
+ AssertSql(
+ """
+SELECT [n].[Id], [n].[Bool], [n].[Byte], [n].[ByteArray], [n].[DateOnly], [n].[DateTime], [n].[DateTimeOffset], [n].[Decimal], [n].[Double], [n].[Enum], [n].[FlagsEnum], [n].[Float], [n].[Guid], [n].[Int], [n].[Long], [n].[Short], [n].[String], [n].[TimeOnly], [n].[TimeSpan]
+FROM [NullableBasicTypesEntities] AS [n]
+WHERE [n].[Int] > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_equality_left(bool async)
+ {
+ await base.Conditional_uncoalesce_with_equality_left(async);
+
+ AssertSql(
+ """
+SELECT [b].[Id], [b].[Bool], [b].[Byte], [b].[ByteArray], [b].[DateOnly], [b].[DateTime], [b].[DateTimeOffset], [b].[Decimal], [b].[Double], [b].[Enum], [b].[FlagsEnum], [b].[Float], [b].[Guid], [b].[Int], [b].[Long], [b].[Short], [b].[String], [b].[TimeOnly], [b].[TimeSpan]
+FROM [BasicTypesEntities] AS [b]
+WHERE NULLIF([b].[Int], 9) > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_equality_right(bool async)
+ {
+ await base.Conditional_uncoalesce_with_equality_right(async);
+
+ AssertSql(
+ """
+SELECT [b].[Id], [b].[Bool], [b].[Byte], [b].[ByteArray], [b].[DateOnly], [b].[DateTime], [b].[DateTimeOffset], [b].[Decimal], [b].[Double], [b].[Enum], [b].[FlagsEnum], [b].[Float], [b].[Guid], [b].[Int], [b].[Long], [b].[Short], [b].[String], [b].[TimeOnly], [b].[TimeSpan]
+FROM [BasicTypesEntities] AS [b]
+WHERE NULLIF([b].[Int], 9) > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_unequality_left(bool async)
+ {
+ await base.Conditional_uncoalesce_with_unequality_left(async);
+
+ AssertSql(
+ """
+SELECT [b].[Id], [b].[Bool], [b].[Byte], [b].[ByteArray], [b].[DateOnly], [b].[DateTime], [b].[DateTimeOffset], [b].[Decimal], [b].[Double], [b].[Enum], [b].[FlagsEnum], [b].[Float], [b].[Guid], [b].[Int], [b].[Long], [b].[Short], [b].[String], [b].[TimeOnly], [b].[TimeSpan]
+FROM [BasicTypesEntities] AS [b]
+WHERE NULLIF([b].[Int], 9) > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_inequality_right(bool async)
+ {
+ await base.Conditional_uncoalesce_with_inequality_right(async);
+
+ AssertSql(
+ """
+SELECT [b].[Id], [b].[Bool], [b].[Byte], [b].[ByteArray], [b].[DateOnly], [b].[DateTime], [b].[DateTimeOffset], [b].[Decimal], [b].[Double], [b].[Enum], [b].[FlagsEnum], [b].[Float], [b].[Guid], [b].[Int], [b].[Long], [b].[Short], [b].[String], [b].[TimeOnly], [b].[TimeSpan]
+FROM [BasicTypesEntities] AS [b]
+WHERE NULLIF([b].[Int], 9) > 1
+""");
+ }
+
+ #endregion Conditional
+
#region Bitwise
public override async Task Bitwise_or(bool async)
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
index 6038f2f2c53..c2107c10d5c 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/GearsOfWarQuerySqliteTest.cs
@@ -2618,9 +2618,7 @@ public override async Task Select_null_propagation_works_for_multiple_navigation
AssertSql(
"""
-SELECT CASE
- WHEN "c"."Name" IS NOT NULL THEN "c"."Name"
-END
+SELECT "c"."Name"
FROM "Tags" AS "t"
LEFT JOIN "Gears" AS "g" ON "t"."GearNickName" = "g"."Nickname" AND "t"."GearSquadId" = "g"."SquadId"
LEFT JOIN "Tags" AS "t0" ON ("g"."Nickname" = "t0"."GearNickName" OR ("g"."Nickname" IS NULL AND "t0"."GearNickName" IS NULL)) AND ("g"."SquadId" = "t0"."GearSquadId" OR ("g"."SquadId" IS NULL AND "t0"."GearSquadId" IS NULL))
@@ -5600,9 +5598,7 @@ public override async Task Select_null_conditional_with_inheritance(bool async)
AssertSql(
"""
-SELECT CASE
- WHEN "f"."CommanderName" IS NOT NULL THEN "f"."CommanderName"
-END
+SELECT "f"."CommanderName"
FROM "Factions" AS "f"
""");
}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/Translations/OperatorTranslationsSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/Translations/OperatorTranslationsSqliteTest.cs
index cbedc68377b..b8da96607b9 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/Translations/OperatorTranslationsSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/Translations/OperatorTranslationsSqliteTest.cs
@@ -12,6 +12,82 @@ public OperatorTranslationsSqliteTest(BasicTypesQuerySqliteFixture fixture, ITes
Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper);
}
+ #region Conditional
+
+ public override async Task Conditional_simplifiable_equality(bool async)
+ {
+ await base.Conditional_simplifiable_equality(async);
+
+ AssertSql(
+ """
+SELECT "n"."Id", "n"."Bool", "n"."Byte", "n"."ByteArray", "n"."DateOnly", "n"."DateTime", "n"."DateTimeOffset", "n"."Decimal", "n"."Double", "n"."Enum", "n"."FlagsEnum", "n"."Float", "n"."Guid", "n"."Int", "n"."Long", "n"."Short", "n"."String", "n"."TimeOnly", "n"."TimeSpan"
+FROM "NullableBasicTypesEntities" AS "n"
+WHERE "n"."Int" > 1
+""");
+ }
+
+ public override async Task Conditional_simplifiable_inequality(bool async)
+ {
+ await base.Conditional_simplifiable_inequality(async);
+
+ AssertSql(
+ """
+SELECT "n"."Id", "n"."Bool", "n"."Byte", "n"."ByteArray", "n"."DateOnly", "n"."DateTime", "n"."DateTimeOffset", "n"."Decimal", "n"."Double", "n"."Enum", "n"."FlagsEnum", "n"."Float", "n"."Guid", "n"."Int", "n"."Long", "n"."Short", "n"."String", "n"."TimeOnly", "n"."TimeSpan"
+FROM "NullableBasicTypesEntities" AS "n"
+WHERE "n"."Int" > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_equality_left(bool async)
+ {
+ await base.Conditional_uncoalesce_with_equality_left(async);
+
+ AssertSql(
+ """
+SELECT "b"."Id", "b"."Bool", "b"."Byte", "b"."ByteArray", "b"."DateOnly", "b"."DateTime", "b"."DateTimeOffset", "b"."Decimal", "b"."Double", "b"."Enum", "b"."FlagsEnum", "b"."Float", "b"."Guid", "b"."Int", "b"."Long", "b"."Short", "b"."String", "b"."TimeOnly", "b"."TimeSpan"
+FROM "BasicTypesEntities" AS "b"
+WHERE NULLIF("b"."Int", 9) > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_equality_right(bool async)
+ {
+ await base.Conditional_uncoalesce_with_equality_right(async);
+
+ AssertSql(
+ """
+SELECT "b"."Id", "b"."Bool", "b"."Byte", "b"."ByteArray", "b"."DateOnly", "b"."DateTime", "b"."DateTimeOffset", "b"."Decimal", "b"."Double", "b"."Enum", "b"."FlagsEnum", "b"."Float", "b"."Guid", "b"."Int", "b"."Long", "b"."Short", "b"."String", "b"."TimeOnly", "b"."TimeSpan"
+FROM "BasicTypesEntities" AS "b"
+WHERE NULLIF("b"."Int", 9) > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_unequality_left(bool async)
+ {
+ await base.Conditional_uncoalesce_with_unequality_left(async);
+
+ AssertSql(
+ """
+SELECT "b"."Id", "b"."Bool", "b"."Byte", "b"."ByteArray", "b"."DateOnly", "b"."DateTime", "b"."DateTimeOffset", "b"."Decimal", "b"."Double", "b"."Enum", "b"."FlagsEnum", "b"."Float", "b"."Guid", "b"."Int", "b"."Long", "b"."Short", "b"."String", "b"."TimeOnly", "b"."TimeSpan"
+FROM "BasicTypesEntities" AS "b"
+WHERE NULLIF("b"."Int", 9) > 1
+""");
+ }
+
+ public override async Task Conditional_uncoalesce_with_inequality_right(bool async)
+ {
+ await base.Conditional_uncoalesce_with_inequality_right(async);
+
+ AssertSql(
+ """
+SELECT "b"."Id", "b"."Bool", "b"."Byte", "b"."ByteArray", "b"."DateOnly", "b"."DateTime", "b"."DateTimeOffset", "b"."Decimal", "b"."Double", "b"."Enum", "b"."FlagsEnum", "b"."Float", "b"."Guid", "b"."Int", "b"."Long", "b"."Short", "b"."String", "b"."TimeOnly", "b"."TimeSpan"
+FROM "BasicTypesEntities" AS "b"
+WHERE NULLIF("b"."Int", 9) > 1
+""");
+ }
+
+ #endregion Conditional
+
#region Bitwise
public override async Task Bitwise_or(bool async)