diff --git a/src/EFCore.Relational/Query/ExpressionVisitors/SqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/ExpressionVisitors/SqlTranslatingExpressionVisitor.cs index b86d1f69e1f..9d3cd4a8361 100644 --- a/src/EFCore.Relational/Query/ExpressionVisitors/SqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/ExpressionVisitors/SqlTranslatingExpressionVisitor.cs @@ -487,14 +487,14 @@ private static Expression UnfoldStructuralComparison(ExpressionType expressionTy if (leftExpressions.Length == 1 && expressionType == ExpressionType.Equal) { - var translatedExpression = TransformNullComparison(leftExpressions[0], rightExpressions[0], binaryExpression.NodeType) - ?? Expression.MakeBinary(expressionType, leftExpressions[0], rightExpressions[0]); - return Expression.AndAlso(translatedExpression, Expression.Constant(true, translatedExpression.Type)); + var translatedExpression = TransformNullComparison(leftExpressions[0], rightExpressions[0], expressionType) + ?? Expression.Equal(leftExpressions[0], rightExpressions[0]); + return Expression.AndAlso(translatedExpression, Expression.Constant(true, typeof(bool))); } return leftExpressions .Zip(rightExpressions, (l, r) => - TransformNullComparison(l, r, binaryExpression.NodeType) + TransformNullComparison(l, r, expressionType) ?? Expression.MakeBinary(expressionType, l, r)) .Aggregate((e1, e2) => expressionType == ExpressionType.Equal diff --git a/src/EFCore.Specification.Tests/QueryTestBase.cs b/src/EFCore.Specification.Tests/QueryTestBase.cs index 410a34cf98f..54b9fe1557d 100644 --- a/src/EFCore.Specification.Tests/QueryTestBase.cs +++ b/src/EFCore.Specification.Tests/QueryTestBase.cs @@ -6191,7 +6191,7 @@ public virtual void Select_Where_Subquery_Equality() var orders = (from o in context.Orders.Take(2) // ReSharper disable once UseMethodAny.0 - where (from od in context.OrderDetails.Take(2) + where (from od in context.OrderDetails.OrderBy(od => od.OrderID).Take(2) where (from c in context.Set() where c.CustomerID == o.CustomerID orderby c.CustomerID diff --git a/src/EFCore/Query/ExpressionVisitors/Internal/TransformingQueryModelExpressionVisitor.cs b/src/EFCore/Query/ExpressionVisitors/Internal/TransformingQueryModelExpressionVisitor.cs new file mode 100644 index 00000000000..288538ab3d6 --- /dev/null +++ b/src/EFCore/Query/ExpressionVisitors/Internal/TransformingQueryModelExpressionVisitor.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Linq.Expressions; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Utilities; +using Remotion.Linq; +using Remotion.Linq.Clauses.Expressions; + +namespace Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal +{ + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public class TransformingQueryModelExpressionVisitor : ExpressionVisitorBase + where TVisitor : IQueryModelVisitor + { + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + protected virtual TVisitor TransformingQueryModelVisitor { get; } + + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + public TransformingQueryModelExpressionVisitor([NotNull] TVisitor transformingQueryModelVisitor) + { + Check.NotNull(transformingQueryModelVisitor, nameof(transformingQueryModelVisitor)); + + TransformingQueryModelVisitor = transformingQueryModelVisitor; + } + + /// + /// This API supports the Entity Framework Core infrastructure and is not intended to be used + /// directly from your code. This API may change or be removed in future releases. + /// + protected override Expression VisitSubQuery(SubQueryExpression expression) + { + TransformingQueryModelVisitor.VisitQueryModel(expression.QueryModel); + + return base.VisitSubQuery(expression); + } + } +} diff --git a/src/EFCore/Query/Internal/QueryOptimizer.cs b/src/EFCore/Query/Internal/QueryOptimizer.cs index 7b3b077c888..1a6b69117a6 100644 --- a/src/EFCore/Query/Internal/QueryOptimizer.cs +++ b/src/EFCore/Query/Internal/QueryOptimizer.cs @@ -8,6 +8,7 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Extensions.Internal; using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal; using Microsoft.EntityFrameworkCore.Query.ResultOperators; using Microsoft.EntityFrameworkCore.Utilities; using Remotion.Linq; @@ -76,6 +77,7 @@ public virtual void Optimize( _queryAnnotations = queryAnnotations; VisitQueryModel(queryModel); + queryModel.TransformExpressions(e => new TransformingQueryModelExpressionVisitor(this).Visit(e)); } /// @@ -175,11 +177,12 @@ protected override void FlattenSubQuery( VisitQueryModel(subQueryModel); - if (subQueryModel.ResultOperators - .All(ro => ro is CastResultOperator) + if ((subQueryModel.ResultOperators.All(ro => ro is CastResultOperator) && !subQueryModel.BodyClauses.Any(bc => bc is OrderByClause) || queryModel.IsIdentityQuery() && !queryModel.ResultOperators.Any()) + || (!queryModel.BodyClauses.Any() + && !subQueryModel.ResultOperators.Any(ro => ro is GroupResultOperator))) { string itemName; @@ -257,14 +260,14 @@ public override void VisitResultOperator(ResultOperatorBase resultOperator, Quer { var oldQuerySource = queryModel.MainFromClause; - var entityQueryProvider + var entityQueryProvider = ((oldQuerySource.FromExpression as ConstantExpression)?.Value as IQueryable)?.Provider as IAsyncQueryProvider; if (entityQueryProvider != null) { queryModel.ResultOperators.RemoveAt(index); - var newMainFromClause + var newMainFromClause = new MainFromClause( oldQuerySource.ItemName, entityType.ClrType, diff --git a/test/EFCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs index 2ec742205af..a31c98c1b47 100644 --- a/test/EFCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs @@ -1826,15 +1826,11 @@ public override void Order_by_key_of_projected_navigation_doesnt_get_optimized_i Assert.Contains( @"@__p_0: 10 -SELECT [l2.OneToOne_Required_FK_Inverse].[Name] -FROM ( - SELECT TOP(@__p_0) [l3.OneToOne_Required_FK_Inverse].* - FROM [Level3] AS [l3] - INNER JOIN [Level2] AS [l3.OneToOne_Required_FK_Inverse] ON [l3].[Level2_Required_Id] = [l3.OneToOne_Required_FK_Inverse].[Id] - ORDER BY [l3.OneToOne_Required_FK_Inverse].[Id] -) AS [t] -INNER JOIN [Level1] AS [l2.OneToOne_Required_FK_Inverse] ON [t].[Level1_Required_Id] = [l2.OneToOne_Required_FK_Inverse].[Id] -ORDER BY [t].[Id]", +SELECT TOP(@__p_0) [l3.OneToOne_Required_FK_Inverse.OneToOne_Required_FK_Inverse].[Name] +FROM [Level3] AS [l3] +INNER JOIN [Level2] AS [l3.OneToOne_Required_FK_Inverse] ON [l3].[Level2_Required_Id] = [l3.OneToOne_Required_FK_Inverse].[Id] +INNER JOIN [Level1] AS [l3.OneToOne_Required_FK_Inverse.OneToOne_Required_FK_Inverse] ON [l3.OneToOne_Required_FK_Inverse].[Level1_Required_Id] = [l3.OneToOne_Required_FK_Inverse.OneToOne_Required_FK_Inverse].[Id] +ORDER BY [l3].[Level2_Required_Id]", Sql); } @@ -1845,10 +1841,10 @@ public override void Order_by_key_of_anonymous_type_projected_navigation_doesnt_ Assert.Equal( @"@__p_0: 10 -SELECT TOP(@__p_0) [l3.OneToOne_Required_FK_Inverse0].[Id], [l3.OneToOne_Required_FK_Inverse0].[Date], [l3.OneToOne_Required_FK_Inverse0].[Level1_Optional_Id], [l3.OneToOne_Required_FK_Inverse0].[Level1_Required_Id], [l3.OneToOne_Required_FK_Inverse0].[Name], [l3.OneToOne_Required_FK_Inverse0].[OneToMany_Optional_InverseId], [l3.OneToOne_Required_FK_Inverse0].[OneToMany_Optional_Self_InverseId], [l3.OneToOne_Required_FK_Inverse0].[OneToMany_Required_InverseId], [l3.OneToOne_Required_FK_Inverse0].[OneToMany_Required_Self_InverseId], [l3.OneToOne_Required_FK_Inverse0].[OneToOne_Optional_PK_InverseId], [l3.OneToOne_Required_FK_Inverse0].[OneToOne_Optional_SelfId], [l30].[Name] -FROM [Level3] AS [l30] -INNER JOIN [Level2] AS [l3.OneToOne_Required_FK_Inverse0] ON [l30].[Level2_Required_Id] = [l3.OneToOne_Required_FK_Inverse0].[Id] -ORDER BY [l3.OneToOne_Required_FK_Inverse0].[Id]", +SELECT TOP(@__p_0) [l3.OneToOne_Required_FK_Inverse].[Id], [l3.OneToOne_Required_FK_Inverse].[Date], [l3.OneToOne_Required_FK_Inverse].[Level1_Optional_Id], [l3.OneToOne_Required_FK_Inverse].[Level1_Required_Id], [l3.OneToOne_Required_FK_Inverse].[Name], [l3.OneToOne_Required_FK_Inverse].[OneToMany_Optional_InverseId], [l3.OneToOne_Required_FK_Inverse].[OneToMany_Optional_Self_InverseId], [l3.OneToOne_Required_FK_Inverse].[OneToMany_Required_InverseId], [l3.OneToOne_Required_FK_Inverse].[OneToMany_Required_Self_InverseId], [l3.OneToOne_Required_FK_Inverse].[OneToOne_Optional_PK_InverseId], [l3.OneToOne_Required_FK_Inverse].[OneToOne_Optional_SelfId], [l3].[Name] +FROM [Level3] AS [l3] +INNER JOIN [Level2] AS [l3.OneToOne_Required_FK_Inverse] ON [l3].[Level2_Required_Id] = [l3.OneToOne_Required_FK_Inverse].[Id] +ORDER BY [l3].[Level2_Required_Id]", Sql); } @@ -1868,13 +1864,10 @@ public override void Projection_select_correct_table_from_subquery_when_material Assert.Equal( @"@__p_0: 3 -SELECT [t].[Name] -FROM ( - SELECT TOP(@__p_0) [l2].* - FROM [Level2] AS [l2] - INNER JOIN [Level1] AS [l2.OneToOne_Required_FK_Inverse] ON [l2].[Level1_Required_Id] = [l2.OneToOne_Required_FK_Inverse].[Id] - WHERE [l2.OneToOne_Required_FK_Inverse].[Name] = N'L1 03' -) AS [t]", +SELECT TOP(@__p_0) [l2].[Name] +FROM [Level2] AS [l2] +INNER JOIN [Level1] AS [l2.OneToOne_Required_FK_Inverse] ON [l2].[Level1_Required_Id] = [l2.OneToOne_Required_FK_Inverse].[Id] +WHERE [l2.OneToOne_Required_FK_Inverse].[Name] = N'L1 03'", Sql); } @@ -1885,11 +1878,11 @@ public override void Projection_select_correct_table_with_anonymous_projection_i Assert.Equal( @"@__p_0: 3 -SELECT TOP(@__p_0) [l20].[Id], [l20].[Date], [l20].[Level1_Optional_Id], [l20].[Level1_Required_Id], [l20].[Name], [l20].[OneToMany_Optional_InverseId], [l20].[OneToMany_Optional_Self_InverseId], [l20].[OneToMany_Required_InverseId], [l20].[OneToMany_Required_Self_InverseId], [l20].[OneToOne_Optional_PK_InverseId], [l20].[OneToOne_Optional_SelfId], [l10].[Id], [l10].[Date], [l10].[Name], [l10].[OneToMany_Optional_Self_InverseId], [l10].[OneToMany_Required_Self_InverseId], [l10].[OneToOne_Optional_SelfId] -FROM [Level2] AS [l20] -INNER JOIN [Level1] AS [l10] ON [l20].[Level1_Required_Id] = [l10].[Id] -INNER JOIN [Level3] AS [l30] ON [l10].[Id] = [l30].[Level2_Required_Id] -WHERE ([l10].[Name] = N'L1 03') AND ([l30].[Name] = N'L3 08')", +SELECT TOP(@__p_0) [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_InverseId], [l2].[OneToMany_Optional_Self_InverseId], [l2].[OneToMany_Required_InverseId], [l2].[OneToMany_Required_Self_InverseId], [l2].[OneToOne_Optional_PK_InverseId], [l2].[OneToOne_Optional_SelfId], [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId] +FROM [Level2] AS [l2] +INNER JOIN [Level1] AS [l1] ON [l2].[Level1_Required_Id] = [l1].[Id] +INNER JOIN [Level3] AS [l3] ON [l1].[Id] = [l3].[Level2_Required_Id] +WHERE ([l1].[Name] = N'L1 03') AND ([l3].[Name] = N'L3 08')", Sql); } @@ -1900,14 +1893,11 @@ public override void Projection_select_correct_table_in_subquery_when_materializ Assert.Equal( @"@__p_0: 3 -SELECT [t].[Name] -FROM ( - SELECT TOP(@__p_0) [l1].* - FROM [Level2] AS [l2] - INNER JOIN [Level1] AS [l1] ON [l2].[Level1_Required_Id] = [l1].[Id] - INNER JOIN [Level3] AS [l3] ON [l1].[Id] = [l3].[Level2_Required_Id] - WHERE ([l1].[Name] = N'L1 03') AND ([l3].[Name] = N'L3 08') -) AS [t]", +SELECT TOP(@__p_0) [l1].[Name] +FROM [Level2] AS [l2] +INNER JOIN [Level1] AS [l1] ON [l2].[Level1_Required_Id] = [l1].[Id] +INNER JOIN [Level3] AS [l3] ON [l1].[Id] = [l3].[Level2_Required_Id] +WHERE ([l1].[Name] = N'L1 03') AND ([l3].[Name] = N'L3 08')", Sql); } @@ -2324,12 +2314,9 @@ public override void Contains_with_subquery_optional_navigation_and_constant_ite FROM [Level1] AS [l1] LEFT JOIN [Level2] AS [l1.OneToOne_Optional_FK] ON [l1].[Id] = [l1.OneToOne_Optional_FK].[Level1_Optional_Id] WHERE 1 IN ( - SELECT [t].[Id] - FROM ( - SELECT DISTINCT [l].* - FROM [Level3] AS [l] - WHERE [l1.OneToOne_Optional_FK].[Id] = [l].[OneToMany_Optional_InverseId] - ) AS [t] + SELECT DISTINCT [l3].[Id] + FROM [Level3] AS [l3] + WHERE [l1.OneToOne_Optional_FK].[Id] = [l3].[OneToMany_Optional_InverseId] )", Sql); } @@ -2350,15 +2337,10 @@ public override void GroupJoin_on_left_side_being_a_subquery() Assert.Equal( @"@__p_0: 2 -SELECT [t].[Id], [t].[Date], [t].[Name], [t].[OneToMany_Optional_Self_InverseId], [t].[OneToMany_Required_Self_InverseId], [t].[OneToOne_Optional_SelfId], [t].[c0], [t].[c1], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[c2], [t].[OneToMany_Optional_InverseId], [t].[c3], [t].[OneToMany_Required_InverseId], [t].[c4], [t].[OneToOne_Optional_PK_InverseId], [t].[c5], [x.OneToOne_Optional_FK].[Id], [x.OneToOne_Optional_FK].[Date], [x.OneToOne_Optional_FK].[Level1_Optional_Id], [x.OneToOne_Optional_FK].[Level1_Required_Id], [x.OneToOne_Optional_FK].[Name], [x.OneToOne_Optional_FK].[OneToMany_Optional_InverseId], [x.OneToOne_Optional_FK].[OneToMany_Optional_Self_InverseId], [x.OneToOne_Optional_FK].[OneToMany_Required_InverseId], [x.OneToOne_Optional_FK].[OneToMany_Required_Self_InverseId], [x.OneToOne_Optional_FK].[OneToOne_Optional_PK_InverseId], [x.OneToOne_Optional_FK].[OneToOne_Optional_SelfId] -FROM ( - SELECT TOP(@__p_0) [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l1.OneToOne_Optional_FK].[Id] AS [c0], [l1.OneToOne_Optional_FK].[Date] AS [c1], [l1.OneToOne_Optional_FK].[Level1_Optional_Id], [l1.OneToOne_Optional_FK].[Level1_Required_Id], [l1.OneToOne_Optional_FK].[Name] AS [c2], [l1.OneToOne_Optional_FK].[OneToMany_Optional_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Optional_Self_InverseId] AS [c3], [l1.OneToOne_Optional_FK].[OneToMany_Required_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Required_Self_InverseId] AS [c4], [l1.OneToOne_Optional_FK].[OneToOne_Optional_PK_InverseId], [l1.OneToOne_Optional_FK].[OneToOne_Optional_SelfId] AS [c5] - FROM [Level1] AS [l1] - LEFT JOIN [Level2] AS [l1.OneToOne_Optional_FK] ON [l1].[Id] = [l1.OneToOne_Optional_FK].[Level1_Optional_Id] - ORDER BY [l1.OneToOne_Optional_FK].[Name] -) AS [t] -LEFT JOIN [Level2] AS [x.OneToOne_Optional_FK] ON [t].[Id] = [x.OneToOne_Optional_FK].[Level1_Optional_Id] -ORDER BY [t].[Name]", +SELECT TOP(@__p_0) [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l1.OneToOne_Optional_FK].[Id], [l1.OneToOne_Optional_FK].[Date], [l1.OneToOne_Optional_FK].[Level1_Optional_Id], [l1.OneToOne_Optional_FK].[Level1_Required_Id], [l1.OneToOne_Optional_FK].[Name], [l1.OneToOne_Optional_FK].[OneToMany_Optional_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Optional_Self_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Required_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Required_Self_InverseId], [l1.OneToOne_Optional_FK].[OneToOne_Optional_PK_InverseId], [l1.OneToOne_Optional_FK].[OneToOne_Optional_SelfId] +FROM [Level1] AS [l1] +LEFT JOIN [Level2] AS [l1.OneToOne_Optional_FK] ON [l1].[Id] = [l1.OneToOne_Optional_FK].[Level1_Optional_Id] +ORDER BY [l1.OneToOne_Optional_FK].[Name]", Sql); } @@ -2538,13 +2520,10 @@ public override void Optional_navigation_in_subquery_with_unrelated_projection() Assert.Equal( @"@__p_0: 15 -SELECT [t].[Id], [t].[Date], [t].[Name], [t].[OneToMany_Optional_Self_InverseId], [t].[OneToMany_Required_Self_InverseId], [t].[OneToOne_Optional_SelfId], [t].[c0], [t].[c1], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[c2], [t].[OneToMany_Optional_InverseId], [t].[c3], [t].[OneToMany_Required_InverseId], [t].[c4], [t].[OneToOne_Optional_PK_InverseId], [t].[c5] -FROM ( - SELECT TOP(@__p_0) [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l1.OneToOne_Optional_FK].[Id] AS [c0], [l1.OneToOne_Optional_FK].[Date] AS [c1], [l1.OneToOne_Optional_FK].[Level1_Optional_Id], [l1.OneToOne_Optional_FK].[Level1_Required_Id], [l1.OneToOne_Optional_FK].[Name] AS [c2], [l1.OneToOne_Optional_FK].[OneToMany_Optional_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Optional_Self_InverseId] AS [c3], [l1.OneToOne_Optional_FK].[OneToMany_Required_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Required_Self_InverseId] AS [c4], [l1.OneToOne_Optional_FK].[OneToOne_Optional_PK_InverseId], [l1.OneToOne_Optional_FK].[OneToOne_Optional_SelfId] AS [c5] - FROM [Level1] AS [l1] - LEFT JOIN [Level2] AS [l1.OneToOne_Optional_FK] ON [l1].[Id] = [l1.OneToOne_Optional_FK].[Level1_Optional_Id] - WHERE ([l1.OneToOne_Optional_FK].[Name] <> N'Foo') OR [l1.OneToOne_Optional_FK].[Name] IS NULL -) AS [t]", +SELECT TOP(@__p_0) [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l1.OneToOne_Optional_FK].[Id], [l1.OneToOne_Optional_FK].[Date], [l1.OneToOne_Optional_FK].[Level1_Optional_Id], [l1.OneToOne_Optional_FK].[Level1_Required_Id], [l1.OneToOne_Optional_FK].[Name], [l1.OneToOne_Optional_FK].[OneToMany_Optional_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Optional_Self_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Required_InverseId], [l1.OneToOne_Optional_FK].[OneToMany_Required_Self_InverseId], [l1.OneToOne_Optional_FK].[OneToOne_Optional_PK_InverseId], [l1.OneToOne_Optional_FK].[OneToOne_Optional_SelfId] +FROM [Level1] AS [l1] +LEFT JOIN [Level2] AS [l1.OneToOne_Optional_FK] ON [l1].[Id] = [l1.OneToOne_Optional_FK].[Level1_Optional_Id] +WHERE ([l1.OneToOne_Optional_FK].[Name] <> N'Foo') OR [l1.OneToOne_Optional_FK].[Name] IS NULL", Sql); } @@ -2555,13 +2534,10 @@ public override void Explicit_GroupJoin_in_subquery_with_unrelated_projection() Assert.Equal( @"@__p_0: 15 -SELECT [t].[Id], [t].[Date], [t].[Name], [t].[OneToMany_Optional_Self_InverseId], [t].[OneToMany_Required_Self_InverseId], [t].[OneToOne_Optional_SelfId], [t].[c0], [t].[c1], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[c2], [t].[OneToMany_Optional_InverseId], [t].[c3], [t].[OneToMany_Required_InverseId], [t].[c4], [t].[OneToOne_Optional_PK_InverseId], [t].[c5] -FROM ( - SELECT TOP(@__p_0) [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l2].[Id] AS [c0], [l2].[Date] AS [c1], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name] AS [c2], [l2].[OneToMany_Optional_InverseId], [l2].[OneToMany_Optional_Self_InverseId] AS [c3], [l2].[OneToMany_Required_InverseId], [l2].[OneToMany_Required_Self_InverseId] AS [c4], [l2].[OneToOne_Optional_PK_InverseId], [l2].[OneToOne_Optional_SelfId] AS [c5] - FROM [Level1] AS [l1] - LEFT JOIN [Level2] AS [l2] ON [l1].[Id] = [l2].[Level1_Optional_Id] - WHERE ([l2].[Name] <> N'Foo') OR [l2].[Name] IS NULL -) AS [t]", +SELECT TOP(@__p_0) [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_InverseId], [l2].[OneToMany_Optional_Self_InverseId], [l2].[OneToMany_Required_InverseId], [l2].[OneToMany_Required_Self_InverseId], [l2].[OneToOne_Optional_PK_InverseId], [l2].[OneToOne_Optional_SelfId] +FROM [Level1] AS [l1] +LEFT JOIN [Level2] AS [l2] ON [l1].[Id] = [l2].[Level1_Optional_Id] +WHERE ([l2].[Name] <> N'Foo') OR [l2].[Name] IS NULL", Sql); } @@ -2570,10 +2546,10 @@ public override void Explicit_GroupJoin_in_subquery_with_unrelated_projection2() base.Explicit_GroupJoin_in_subquery_with_unrelated_projection2(); Assert.Equal( - @"SELECT [l10].[Id], [l10].[Date], [l10].[Name], [l10].[OneToMany_Optional_Self_InverseId], [l10].[OneToMany_Required_Self_InverseId], [l10].[OneToOne_Optional_SelfId], [l20].[Id], [l20].[Date], [l20].[Level1_Optional_Id], [l20].[Level1_Required_Id], [l20].[Name], [l20].[OneToMany_Optional_InverseId], [l20].[OneToMany_Optional_Self_InverseId], [l20].[OneToMany_Required_InverseId], [l20].[OneToMany_Required_Self_InverseId], [l20].[OneToOne_Optional_PK_InverseId], [l20].[OneToOne_Optional_SelfId] -FROM [Level1] AS [l10] -LEFT JOIN [Level2] AS [l20] ON [l10].[Id] = [l20].[Level1_Optional_Id] -WHERE ([l20].[Name] <> N'Foo') OR [l20].[Name] IS NULL", + @"SELECT [l1].[Id], [l1].[Date], [l1].[Name], [l1].[OneToMany_Optional_Self_InverseId], [l1].[OneToMany_Required_Self_InverseId], [l1].[OneToOne_Optional_SelfId], [l2].[Id], [l2].[Date], [l2].[Level1_Optional_Id], [l2].[Level1_Required_Id], [l2].[Name], [l2].[OneToMany_Optional_InverseId], [l2].[OneToMany_Optional_Self_InverseId], [l2].[OneToMany_Required_InverseId], [l2].[OneToMany_Required_Self_InverseId], [l2].[OneToOne_Optional_PK_InverseId], [l2].[OneToOne_Optional_SelfId] +FROM [Level1] AS [l1] +LEFT JOIN [Level2] AS [l2] ON [l1].[Id] = [l2].[Level1_Optional_Id] +WHERE ([l2].[Name] <> N'Foo') OR [l2].[Name] IS NULL", Sql); } @@ -2645,17 +2621,13 @@ public override void Where_on_multilevel_reference_in_subquery_with_outer_projec @"@__p_0: 0 @__p_1: 10 -SELECT [t].[Name] -FROM ( - SELECT [l3].* - FROM [Level3] AS [l3] - INNER JOIN [Level2] AS [l3.OneToMany_Required_Inverse] ON [l3].[OneToMany_Required_InverseId] = [l3.OneToMany_Required_Inverse].[Id] - INNER JOIN [Level1] AS [l3.OneToMany_Required_Inverse.OneToOne_Required_FK_Inverse] ON [l3.OneToMany_Required_Inverse].[Level1_Required_Id] = [l3.OneToMany_Required_Inverse.OneToOne_Required_FK_Inverse].[Id] - WHERE [l3.OneToMany_Required_Inverse.OneToOne_Required_FK_Inverse].[Name] = N'L1 03' - ORDER BY [l3].[Level2_Required_Id] - OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY -) AS [t] -ORDER BY [t].[Level2_Required_Id]", +SELECT [l3].[Name] +FROM [Level3] AS [l3] +INNER JOIN [Level2] AS [l3.OneToMany_Required_Inverse] ON [l3].[OneToMany_Required_InverseId] = [l3.OneToMany_Required_Inverse].[Id] +INNER JOIN [Level1] AS [l3.OneToMany_Required_Inverse.OneToOne_Required_FK_Inverse] ON [l3.OneToMany_Required_Inverse].[Level1_Required_Id] = [l3.OneToMany_Required_Inverse.OneToOne_Required_FK_Inverse].[Id] +WHERE [l3.OneToMany_Required_Inverse.OneToOne_Required_FK_Inverse].[Name] = N'L1 03' +ORDER BY [l3].[Level2_Required_Id] +OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY", Sql); } diff --git a/test/EFCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs index 0bfa190e4ac..41cfc00f5d2 100644 --- a/test/EFCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs @@ -937,15 +937,11 @@ public override void Include_where_skip_take_projection(bool useString) @__p_1: 2 SELECT [od.Order].[CustomerID] -FROM ( - SELECT [od].* - FROM [Order Details] AS [od] - WHERE [od].[Quantity] = 10 - ORDER BY [od].[OrderID], [od].[ProductID] - OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY -) AS [t] -INNER JOIN [Orders] AS [od.Order] ON [t].[OrderID] = [od.Order].[OrderID] -ORDER BY [t].[OrderID], [t].[ProductID]", +FROM [Order Details] AS [od] +INNER JOIN [Orders] AS [od.Order] ON [od].[OrderID] = [od.Order].[OrderID] +WHERE [od].[Quantity] = 10 +ORDER BY [od].[OrderID], [od].[ProductID] +OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY", Sql); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs index 1bdbde4a390..e6e7a13eaab 100644 --- a/test/EFCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs @@ -198,13 +198,9 @@ public override void Take_Select_Navigation() Assert.Equal( @"@__p_0: 2 -SELECT [t].[CustomerID] -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -ORDER BY [t].[CustomerID] +SELECT TOP(@__p_0) [c].[CustomerID] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID] @_outer_CustomerID: ALFKI (Size = 450) @@ -227,17 +223,13 @@ public override void Select_collection_FirstOrDefault_project_single_column1() Assert.Equal( @"@__p_0: 2 -SELECT ( +SELECT TOP(@__p_0) ( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE [t].[CustomerID] = [o].[CustomerID] + WHERE [c].[CustomerID] = [o].[CustomerID] ) -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -ORDER BY [t].[CustomerID]", +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]", Sql); } @@ -248,17 +240,13 @@ public override void Select_collection_FirstOrDefault_project_single_column2() Assert.Equal( @"@__p_0: 2 -SELECT ( +SELECT TOP(@__p_0) ( SELECT TOP(1) [o].[CustomerID] FROM [Orders] AS [o] - WHERE [t].[CustomerID] = [o].[CustomerID] + WHERE [c].[CustomerID] = [o].[CustomerID] ) -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -ORDER BY [t].[CustomerID]", +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]", Sql); } @@ -269,13 +257,9 @@ public override void Select_collection_FirstOrDefault_project_anonymous_type() Assert.Equal( @"@__p_0: 2 -SELECT [t].[CustomerID] -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -ORDER BY [t].[CustomerID] +SELECT TOP(@__p_0) [c].[CustomerID] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID] @_outer_CustomerID: ALFKI (Size = 450) @@ -298,13 +282,9 @@ public override void Select_collection_FirstOrDefault_project_entity() Assert.Equal( @"@__p_0: 2 -SELECT [t].[CustomerID] -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -ORDER BY [t].[CustomerID] +SELECT TOP(@__p_0) [c].[CustomerID] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID] @_outer_CustomerID: ALFKI (Size = 450) @@ -329,14 +309,10 @@ public override void Skip_Select_Navigation() Assert.StartsWith( @"@__p_0: 20 -SELECT [t].[CustomerID] -FROM ( - SELECT [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] - OFFSET @__p_0 ROWS -) AS [t] -ORDER BY [t].[CustomerID] +SELECT [c].[CustomerID] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID] +OFFSET @__p_0 ROWS @_outer_CustomerID: FAMIA (Size = 450) diff --git a/test/EFCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs index 56a1083f2d4..27810c55668 100644 --- a/test/EFCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs @@ -506,10 +506,11 @@ ORDER BY [t].[OrderID] SELECT [t1].[OrderID] FROM ( - SELECT TOP(2) [o1].* - FROM [Order Details] AS [o1] + SELECT TOP(2) [od0].* + FROM [Order Details] AS [od0] + ORDER BY [od0].[OrderID] ) AS [t1] -ORDER BY [t1].[ProductID], [t1].[OrderID] +ORDER BY [t1].[OrderID] @_outer_CustomerID2: VINET (Size = 450) @@ -518,7 +519,7 @@ FROM [Customers] AS [c3] WHERE [c3].[CustomerID] = @_outer_CustomerID2 ORDER BY [c3].[CustomerID] -@_outer_OrderID1: 10285 +@_outer_OrderID1: 10248 SELECT TOP(1) [c4].[Country] FROM [Orders] AS [o20] @@ -528,22 +529,22 @@ FROM [Orders] AS [o20] Sql); } + // TODO: This query can be translated to Server but it does not due to the QueryParser's optimizations. See Issue#7844 public override void Where_subquery_anon() { base.Where_subquery_anon(); - Assert.Equal( + Assert.StartsWith( @"@__p_0: 9 -SELECT [t].[EmployeeID], [t].[City], [t].[Country], [t].[FirstName], [t].[ReportsTo], [t].[Title], [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate] +SELECT [t].[EmployeeID], [t].[City], [t].[Country], [t].[FirstName], [t].[ReportsTo], [t].[Title] FROM ( SELECT TOP(@__p_0) [e].[EmployeeID], [e].[City], [e].[Country], [e].[FirstName], [e].[ReportsTo], [e].[Title] FROM [Employees] AS [e] ) AS [t] -CROSS JOIN ( - SELECT TOP(1000) [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] - FROM [Orders] AS [o] -) AS [t0]", + +SELECT TOP(1000) [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] +FROM [Orders] AS [o0]", Sql); } @@ -1745,11 +1746,8 @@ public override void Queryable_simple_anonymous_projection_subquery() Assert.Equal( @"@__p_0: 91 -SELECT [t].[City] -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] -) AS [t]", +SELECT TOP(@__p_0) [c].[City] +FROM [Customers] AS [c]", Sql); } @@ -1760,8 +1758,8 @@ public override void Queryable_simple_anonymous_subquery() Assert.Equal( @"@__p_0: 91 -SELECT TOP(@__p_0) [c0].[CustomerID], [c0].[Address], [c0].[City], [c0].[CompanyName], [c0].[ContactName], [c0].[ContactTitle], [c0].[Country], [c0].[Fax], [c0].[Phone], [c0].[PostalCode], [c0].[Region] -FROM [Customers] AS [c0]", +SELECT TOP(@__p_0) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM [Customers] AS [c]", Sql); } @@ -1811,13 +1809,9 @@ public override void Take_subquery_projection() Assert.Equal( @"@__p_0: 2 -SELECT [t].[City] -FROM ( - SELECT TOP(@__p_0) [c].* - FROM [Customers] AS [c] - ORDER BY [c].[CustomerID] -) AS [t] -ORDER BY [t].[CustomerID]", +SELECT TOP(@__p_0) [c].[City] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]", Sql); } @@ -2141,11 +2135,8 @@ public override void Select_scalar_primitive_after_take() Assert.Equal( @"@__p_0: 9 -SELECT [t].[EmployeeID] -FROM ( - SELECT TOP(@__p_0) [e].* - FROM [Employees] AS [e] -) AS [t]", +SELECT TOP(@__p_0) [e].[EmployeeID] +FROM [Employees] AS [e]", Sql); } @@ -5015,7 +5006,7 @@ FROM [Order Details] AS [od] WHERE CEILING([od].[UnitPrice]) > 10.0", Sql); } - + public override void Where_math_floor() { base.Where_math_floor(); @@ -5590,12 +5581,9 @@ FROM [Customers] AS [c] @_outer_CustomerID: ALFKI (Size = 450) -SELECT [t].[OrderDate] -FROM ( - SELECT TOP(3) [o].* - FROM [Orders] AS [o] - WHERE ([o].[OrderID] < 10500) AND (@_outer_CustomerID = [o].[CustomerID]) -) AS [t]", +SELECT TOP(3) [o].[OrderDate] +FROM [Orders] AS [o] +WHERE ([o].[OrderID] < 10500) AND (@_outer_CustomerID = [o].[CustomerID])", Sql); } @@ -5611,15 +5599,12 @@ FROM [Customers] AS [c] @_outer_City: Berlin (Size = 6) @_outer_CustomerID: ALFKI (Size = 450) -SELECT [t].[OrderDate] -FROM ( - SELECT TOP(3) [o].* - FROM [Orders] AS [o] - WHERE EXISTS ( - SELECT 1 - FROM [Order Details] AS [d] - WHERE ([d].[Discount] > LEN(@_outer_City)) AND ([o].[OrderID] = [d].[OrderID])) AND (@_outer_CustomerID = [o].[CustomerID]) -) AS [t]", +SELECT TOP(3) [o].[OrderDate] +FROM [Orders] AS [o] +WHERE EXISTS ( + SELECT 1 + FROM [Order Details] AS [d] + WHERE ([d].[Discount] > LEN(@_outer_City)) AND ([o].[OrderID] = [d].[OrderID])) AND (@_outer_CustomerID = [o].[CustomerID])", Sql); } @@ -5647,12 +5632,9 @@ THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT) @_outer_CustomerID: ALFKI (Size = 450) -SELECT [t].[OrderDate] -FROM ( - SELECT TOP(3) [o0].* - FROM [Orders] AS [o0] - WHERE @_outer_CustomerID = [o0].[CustomerID] -) AS [t]", +SELECT TOP(3) [o0].[OrderDate] +FROM [Orders] AS [o0] +WHERE @_outer_CustomerID = [o0].[CustomerID]", Sql); }