diff --git a/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs b/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs index 636f5ed13dc..5ec0059b30c 100644 --- a/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs @@ -143,6 +143,30 @@ private bool PreserveConvertNode(Expression expression) return false; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + protected override Expression VisitConditional(ConditionalExpression conditionalExpression) + { + var newTestExpression = TryGetConstantValue(conditionalExpression.Test) ?? Visit(conditionalExpression.Test); + + if (newTestExpression is ConstantExpression constantTestExpression + && constantTestExpression.Value is bool constantTestValue) + { + return constantTestValue + ? Visit(conditionalExpression.IfTrue) + : Visit(conditionalExpression.IfFalse); + } + + return conditionalExpression.Update( + newTestExpression, + Visit(conditionalExpression.IfTrue), + Visit(conditionalExpression.IfFalse)); + } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in diff --git a/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs index 94c571c43b7..d8f55daf09e 100644 --- a/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.cs @@ -824,6 +824,24 @@ public virtual Task Ternary_should_not_evaluate_both_sides(bool isAsync) })); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Ternary_should_not_evaluate_both_sides_with_parameter(bool isAsync) + { + DateTime? param = null; + + return AssertQuery( + isAsync, + ss => ss.Set().Select( + o => new + { + // ReSharper disable SimplifyConditionalTernaryExpression + Data1 = param != null ? o.OrderDate == param.Value : true, + Data2 = param == null ? true : o.OrderDate == param.Value + // ReSharper restore SimplifyConditionalTernaryExpression + })); + } + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Null_Coalesce_Short_Circuit(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs index 7c092752f8d..78926e176a7 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs @@ -1450,6 +1450,15 @@ public override async Task Ternary_should_not_evaluate_both_sides(bool isAsync) FROM [Customers] AS [c]"); } + public override async Task Ternary_should_not_evaluate_both_sides_with_parameter(bool isAsync) + { + await base.Ternary_should_not_evaluate_both_sides_with_parameter(isAsync); + + AssertSql( + @"SELECT CAST(1 AS bit) AS [Data1] +FROM [Orders] AS [o]"); + } + public override async Task Where_compare_constructed_multi_value_equal(bool isAsync) { await base.Where_compare_constructed_multi_value_equal(isAsync);