From 3ba88c418276c5ba8264a29be42e0d5a39e92c94 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 25 Nov 2024 17:06:49 +0100 Subject: [PATCH] Correct VisitUnary operand evaluation in funcletizer (#35172) Fixes #35152 --- .../Query/Internal/ExpressionTreeFuncletizer.cs | 13 +++++-------- .../Query/NorthwindMiscellaneousQueryCosmosTest.cs | 11 +++++++++++ .../Query/NorthwindMiscellaneousQueryTestBase.cs | 11 +++++++++++ .../NorthwindMiscellaneousQuerySqlServerTest.cs | 11 +++++++++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs b/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs index 7395913e44b..fe7e89b98a4 100644 --- a/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs +++ b/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs @@ -1556,14 +1556,11 @@ UnaryExpression EvaluateOperand(UnaryExpression unary, Expression operand, State operand = ProcessEvaluatableRoot(operand, ref operandState); } - if (_state.ContainsEvaluatable) - { - _state = _calculatingPath - ? State.CreateContainsEvaluatable( - typeof(UnaryExpression), - [_state.Path! with { PathFromParent = static e => Property(e, nameof(UnaryExpression.Operand)) }]) - : State.NoEvaluatability; - } + _state = operandState.ContainsEvaluatable && _calculatingPath + ? State.CreateContainsEvaluatable( + typeof(UnaryExpression), + [_state.Path! with { PathFromParent = static e => Property(e, nameof(UnaryExpression.Operand)) }]) + : State.NoEvaluatability; return unary.Update(operand); } diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs index 5107d20efa5..f1ce8c9417a 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindMiscellaneousQueryCosmosTest.cs @@ -5325,6 +5325,17 @@ public override async Task Column_access_inside_subquery_predicate(bool async) AssertSql(); } + public override async Task Cast_to_object_over_parameter_directly_in_lambda(bool async) + { + // Sync always throws before getting to exception being tested. + if (async) + { + // Cosmos doesn't support ORDER BY over parameter/constant: + // Unsupported ORDER BY clause. ORDER BY item expression could not be mapped to a document path. + await Assert.ThrowsAsync(() => base.Cast_to_object_over_parameter_directly_in_lambda(async: true)); + } + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs index 25c8f9d5cfc..5c553f21d37 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindMiscellaneousQueryTestBase.cs @@ -5897,4 +5897,15 @@ public virtual Task Column_access_inside_subquery_predicate(bool async) => AssertQuery( async, ss => ss.Set().Where(c => ss.Set().Where(o => c.CustomerID == "ALFKI").Any())); + + [ConditionalTheory] // #35152 + [MemberData(nameof(IsAsyncData))] + public virtual Task Cast_to_object_over_parameter_directly_in_lambda(bool async) + { + var i = 8; + + return AssertQuery( + async, + ss => ss.Set().OrderBy(o => (object)i).Select(o => o)); + } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs index 4eb5fa068e0..1845ef6caba 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindMiscellaneousQuerySqlServerTest.cs @@ -7531,6 +7531,17 @@ FROM [Orders] AS [o] """); } + public override async Task Cast_to_object_over_parameter_directly_in_lambda(bool async) + { + await base.Cast_to_object_over_parameter_directly_in_lambda(async); + + AssertSql( + """ +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM [Orders] AS [o] +"""); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected);