diff --git a/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitor.cs index cf090439e36..296c01d2e99 100644 --- a/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitor.cs @@ -15,6 +15,7 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Storage; using Newtonsoft.Json.Linq; diff --git a/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitorFactory.cs b/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitorFactory.cs index 640a763eebc..6f9961e1a82 100644 --- a/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitorFactory.cs +++ b/src/EFCore.Cosmos/Query/Pipeline/CosmosShapedQueryCompilingExpressionVisitorFactory.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Pipeline; namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Pipeline diff --git a/src/EFCore.Cosmos/Query/Pipeline/CosmosSqlTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Pipeline/CosmosSqlTranslatingExpressionVisitor.cs index d35d1e1427e..0573024fc4f 100644 --- a/src/EFCore.Cosmos/Query/Pipeline/CosmosSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Pipeline/CosmosSqlTranslatingExpressionVisitor.cs @@ -37,13 +37,18 @@ public CosmosSqlTranslatingExpressionVisitor( public SqlExpression Translate(Expression expression) { - var translation = (SqlExpression)Visit(expression); + var result = Visit(expression); - translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); + if (result is SqlExpression translation) + { + translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); + + _sqlVerifyingExpressionVisitor.Visit(translation); - _sqlVerifyingExpressionVisitor.Visit(translation); + return translation; + } - return translation; + return null; } private class SqlTypeMappingVerifyingExpressionVisitor : ExpressionVisitor @@ -176,6 +181,14 @@ private static Expression TryRemoveImplicitConvert(Expression expression) protected override Expression VisitBinary(BinaryExpression binaryExpression) { + if (binaryExpression.NodeType == ExpressionType.Coalesce) + { + return Visit(Expression.Condition( + Expression.NotEqual(binaryExpression.Left, Expression.Constant(null, binaryExpression.Left.Type)), + binaryExpression.Left, + binaryExpression.Right)); + } + var left = TryRemoveImplicitConvert(binaryExpression.Left); var right = TryRemoveImplicitConvert(binaryExpression.Right); @@ -264,6 +277,8 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) protected override Expression VisitListInit(ListInitExpression node) => null; + protected override Expression VisitInvocation(InvocationExpression node) => null; + protected override Expression VisitConstant(ConstantExpression constantExpression) => new SqlConstantExpression(constantExpression, null); diff --git a/src/EFCore.Cosmos/Query/Pipeline/SelectExpression.cs b/src/EFCore.Cosmos/Query/Pipeline/SelectExpression.cs index 021a6552ac0..baa1b2633e0 100644 --- a/src/EFCore.Cosmos/Query/Pipeline/SelectExpression.cs +++ b/src/EFCore.Cosmos/Query/Pipeline/SelectExpression.cs @@ -114,8 +114,6 @@ private int AddToProjection(Expression expression, string alias) public void ApplyDistinct() { IsDistinct = true; - - ClearOrdering(); } public void ClearOrdering() diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryMaterializerFactory.cs b/src/EFCore.InMemory/Query/Internal/InMemoryMaterializerFactory.cs index 6e055b69143..cde3370bb2f 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryMaterializerFactory.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryMaterializerFactory.cs @@ -6,6 +6,7 @@ using System.Linq.Expressions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs index 3eb7d80aa57..babd6d56171 100644 --- a/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitor.cs @@ -14,6 +14,7 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Storage; diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitorFactory.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitorFactory.cs index 4fafa7b7770..c9ad4e98ced 100644 --- a/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitorFactory.cs +++ b/src/EFCore.InMemory/Query/Pipeline/InMemoryShapedQueryExpressionVisitorFactory.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Pipeline; namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs index a5840ad827c..05b384abc43 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalProjectionBindingRemovingExpressionVisitor.cs @@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions; using Microsoft.EntityFrameworkCore.Storage; diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryExpressionVisitorFactory.cs b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryExpressionVisitorFactory.cs index 41f1c63497d..e35c23aa3f1 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryExpressionVisitorFactory.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryExpressionVisitorFactory.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Storage; diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs index ec7589b440b..2c3e949fe95 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalSqlTranslatingExpressionVisitor.cs @@ -42,20 +42,25 @@ public RelationalSqlTranslatingExpressionVisitor( public SqlExpression Translate(Expression expression) { - var translation = (SqlExpression)Visit(expression); + var result = Visit(expression); - if (translation is SqlUnaryExpression sqlUnaryExpression - && sqlUnaryExpression.OperatorType == ExpressionType.Convert - && sqlUnaryExpression.Type == typeof(object)) + if (result is SqlExpression translation) { - translation = sqlUnaryExpression.Operand; - } + if (translation is SqlUnaryExpression sqlUnaryExpression + && sqlUnaryExpression.OperatorType == ExpressionType.Convert + && sqlUnaryExpression.Type == typeof(object)) + { + translation = sqlUnaryExpression.Operand; + } + + translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); - translation = _sqlExpressionFactory.ApplyDefaultTypeMapping(translation); + _sqlVerifyingExpressionVisitor.Visit(translation); - _sqlVerifyingExpressionVisitor.Visit(translation); + return translation; + } - return translation; + return null; } private class SqlTypeMappingVerifyingExpressionVisitor : ExpressionVisitor @@ -253,6 +258,9 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) protected override Expression VisitNewArray(NewArrayExpression node) => null; protected override Expression VisitListInit(ListInitExpression node) => null; + + protected override Expression VisitInvocation(InvocationExpression node) => null; + protected override Expression VisitConstant(ConstantExpression constantExpression) => new SqlConstantExpression(constantExpression, null); diff --git a/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs b/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs index 718f69e00c1..9bc4ad5d85b 100644 --- a/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs +++ b/src/EFCore/ChangeTracking/Internal/ArrayPropertyValues.cs @@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; diff --git a/src/EFCore/ChangeTracking/Internal/IStateManager.cs b/src/EFCore/ChangeTracking/Internal/IStateManager.cs index 267593dd526..0c6e94f5a93 100644 --- a/src/EFCore/ChangeTracking/Internal/IStateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/IStateManager.cs @@ -10,6 +10,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Update; using Microsoft.Extensions.DependencyInjection; diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs index 861d8496303..b561a0c244c 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs @@ -12,6 +12,7 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Update; using Microsoft.Extensions.DependencyInjection; diff --git a/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs b/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs index 7e7db0da25e..ea0c63972b4 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManagerDependencies.cs @@ -6,6 +6,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; diff --git a/src/EFCore/Metadata/IEntityMaterializerSource.cs b/src/EFCore/Metadata/IEntityMaterializerSource.cs index 91c083af04c..eed719facd2 100644 --- a/src/EFCore/Metadata/IEntityMaterializerSource.cs +++ b/src/EFCore/Metadata/IEntityMaterializerSource.cs @@ -4,10 +4,11 @@ using System; using System.Linq.Expressions; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.EntityFrameworkCore.Metadata +namespace Microsoft.EntityFrameworkCore.Query { /// /// diff --git a/src/EFCore/Metadata/Internal/EntityMaterializerSource.cs b/src/EFCore/Metadata/Internal/EntityMaterializerSource.cs index 76c95223669..bde686323b3 100644 --- a/src/EFCore/Metadata/Internal/EntityMaterializerSource.cs +++ b/src/EFCore/Metadata/Internal/EntityMaterializerSource.cs @@ -11,10 +11,12 @@ using System.Threading; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Internal; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.EntityFrameworkCore.Metadata.Internal +namespace Microsoft.EntityFrameworkCore.Query.Internal { /// /// diff --git a/src/EFCore/Metadata/PropertyParameterBinding.cs b/src/EFCore/Metadata/PropertyParameterBinding.cs index 778958e1c96..dbc1b917bc9 100644 --- a/src/EFCore/Metadata/PropertyParameterBinding.cs +++ b/src/EFCore/Metadata/PropertyParameterBinding.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Storage; namespace Microsoft.EntityFrameworkCore.Metadata diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosSqlTest.Where.cs b/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosSqlTest.Where.cs index 4b4b61f5152..e531d233272 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosSqlTest.Where.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosSqlTest.Where.cs @@ -352,7 +352,7 @@ await AssertQuery( AssertSql( @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND ((c[""Region""] ?? ""SP"") = ""BC""))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (((c[""Region""] != null) ? c[""Region""] : ""SP"") = ""BC""))"); } public override async Task Where_simple(bool isAsync) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs index 1b20306bd74..3d30f1213d3 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/SimpleQueryCosmosTest.cs @@ -2015,13 +2015,13 @@ FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } - [ConditionalTheory(Skip = "Issue#16152")] + [ConditionalTheory] public override async Task Projection_null_coalesce_operator(bool isAsync) { await base.Projection_null_coalesce_operator(isAsync); AssertSql( - @"SELECT c + @"SELECT c[""CustomerID""], c[""CompanyName""], ((c[""Region""] != null) ? c[""Region""] : ""ZZ"") AS Region FROM root c WHERE (c[""Discriminator""] = ""Customer"")"); } @@ -2033,7 +2033,7 @@ public override async Task Filter_coalesce_operator(bool isAsync) AssertSql( @"SELECT c FROM root c -WHERE ((c[""Discriminator""] = ""Customer"") AND ((c[""CompanyName""] ?? c[""ContactName""]) = ""The Big Cheese""))"); +WHERE ((c[""Discriminator""] = ""Customer"") AND (((c[""CompanyName""] != null) ? c[""CompanyName""] : c[""ContactName""]) = ""The Big Cheese""))"); } [ConditionalTheory(Skip = "Issue #14935")] @@ -3996,6 +3996,12 @@ public override Task Where_string_concat_method_comparison(bool isAsync) return base.Where_string_concat_method_comparison(isAsync); } + [ConditionalTheory(Skip = "Issue #14935")] + public override Task Inner_parameter_in_nested_lambdas_gets_preserved(bool isAsync) + { + return base.Inner_parameter_in_nested_lambdas_gets_preserved(isAsync); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Select.cs b/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Select.cs index 09b0d604340..7af667798cb 100644 --- a/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Select.cs +++ b/test/EFCore.Specification.Tests/Query/SimpleQueryTestBase.Select.cs @@ -895,9 +895,8 @@ public virtual Task Project_single_element_from_collection_with_multiple_OrderBy .FirstOrDefault())); } - // issue #12597 - //[ConditionalTheory] - //[MemberData(nameof(IsAsyncData))] + [ConditionalTheory(Skip = "Issue#12597")] + [MemberData(nameof(IsAsyncData))] public virtual Task Project_single_element_from_collection_with_multiple_OrderBys_Take_and_FirstOrDefault_followed_by_projection_of_length_property( bool isAsync) diff --git a/test/EFCore.Tests/DbContextServicesTest.cs b/test/EFCore.Tests/DbContextServicesTest.cs index f49af5e162b..60d93e0b9c8 100644 --- a/test/EFCore.Tests/DbContextServicesTest.cs +++ b/test/EFCore.Tests/DbContextServicesTest.cs @@ -16,6 +16,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.EntityFrameworkCore.ValueGeneration; using Microsoft.Extensions.Caching.Memory; diff --git a/test/EFCore.Tests/Metadata/Internal/EntityMaterializerSourceTest.cs b/test/EFCore.Tests/Metadata/Internal/EntityMaterializerSourceTest.cs index 241588caf06..cc99e45829e 100644 --- a/test/EFCore.Tests/Metadata/Internal/EntityMaterializerSourceTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/EntityMaterializerSourceTest.cs @@ -7,6 +7,8 @@ using System.Linq.Expressions; using System.Reflection; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Storage; using Xunit; diff --git a/test/EFCore.Tests/TestUtilities/FakeStateManager.cs b/test/EFCore.Tests/TestUtilities/FakeStateManager.cs index 5d69f0682c2..985fffd6f7d 100644 --- a/test/EFCore.Tests/TestUtilities/FakeStateManager.cs +++ b/test/EFCore.Tests/TestUtilities/FakeStateManager.cs @@ -12,6 +12,7 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Update;