diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index b510c493bd2..c07ef8d2c48 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -920,8 +920,8 @@ static Expression RemoveConvert(Expression expression) var actualParentIdentifier = _identifier.Take(outerSelectExpression._identifier.Count).ToList(); for (var j = 0; j < actualParentIdentifier.Count; j++) { - AppendOrdering(new OrderingExpression(actualParentIdentifier[j].Column, ascending: true)); - outerSelectExpression.AppendOrdering( + AppendOrderingInternal(new OrderingExpression(actualParentIdentifier[j].Column, ascending: true)); + outerSelectExpression.AppendOrderingInternal( new OrderingExpression(outerSelectExpression._identifier[j].Column, ascending: true)); } @@ -1860,6 +1860,11 @@ private static void PopulateGroupByTerms( /// An ordering expression to use for ordering. public void ApplyOrdering(OrderingExpression orderingExpression) { + if (Limit is SqlConstantExpression { Value: 1 }) + { + return; + } + if (IsDistinct || Limit != null || Offset != null) @@ -1877,14 +1882,21 @@ public void ApplyOrdering(OrderingExpression orderingExpression) /// An ordering expression to use for ordering. public void AppendOrdering(OrderingExpression orderingExpression) { - if (!_orderings.Any(o => o.Expression.Equals(orderingExpression.Expression))) + if (Limit is SqlConstantExpression { Value: 1 }) { - AppendOrderingInternal(orderingExpression); + return; } + + AppendOrderingInternal(orderingExpression); } private void AppendOrderingInternal(OrderingExpression orderingExpression) - => _orderings.Add(orderingExpression.Update(orderingExpression.Expression)); + { + if (!_orderings.Any(o => o.Expression.Equals(orderingExpression.Expression))) + { + _orderings.Add(orderingExpression); + } + } /// /// Reverses the existing orderings on the . diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index b05fbdf7475..1729032d122 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -722,6 +722,15 @@ public override async Task Project_single_element_from_collection_with_OrderBy_T AssertSql(); } + public override async Task Project_single_element_from_collection_with_OrderBy_Take_OrderBy_and_FirstOrDefault(bool async) + { + // Cosmos client evaluation. Issue #17246. + await AssertTranslationFailed( + () => base.Project_single_element_from_collection_with_OrderBy_Take_OrderBy_and_FirstOrDefault(async)); + + AssertSql(); + } + public override async Task Project_single_element_from_collection_with_OrderBy_Take_and_FirstOrDefault_with_parameter(bool async) { // Cosmos client evaluation. Issue #17246. diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index cbd036ad513..83c1812aaee 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -1017,6 +1017,14 @@ public virtual Task Project_single_element_from_collection_with_OrderBy_Take_and async, ss => ss.Set().Select(c => c.Orders.OrderBy(o => o.OrderID).Select(o => o.CustomerID).Take(1).FirstOrDefault())); + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_single_element_from_collection_with_OrderBy_Take_OrderBy_and_FirstOrDefault(bool async) + => AssertQuery( + async, + ss => ss.Set().Select( + c => c.Orders.OrderBy(o => o.OrderID).Take(1).OrderBy(o => o.OrderDate).FirstOrDefault())); + [ConditionalTheory] [MemberData(nameof(IsAsyncData))] public virtual Task Project_single_element_from_collection_with_OrderBy_Skip_and_FirstOrDefault(bool async) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs index 69f02149536..95aac4827b3 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServer160Test.cs @@ -67,12 +67,8 @@ where l1.Id < 3 AssertSql( """ SELECT ( - SELECT TOP(1) [l1].[Name] - FROM ( - SELECT TOP(1) [l0].[Id], [l0].[Name] - FROM [LevelThree] AS [l0] - ) AS [l1] - ORDER BY [l1].[Id]) + SELECT TOP(1) [l0].[Name] + FROM [LevelThree] AS [l0]) FROM [LevelOne] AS [l] WHERE [l].[Id] < 3 """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 16b4f166b45..92465352e8e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -67,12 +67,8 @@ where l1.Id < 3 AssertSql( """ SELECT ( - SELECT TOP(1) [l1].[Name] - FROM ( - SELECT TOP(1) [l0].[Id], [l0].[Name] - FROM [LevelThree] AS [l0] - ) AS [l1] - ORDER BY [l1].[Id]) + SELECT TOP(1) [l0].[Name] + FROM [LevelThree] AS [l0]) FROM [LevelOne] AS [l] WHERE [l].[Id] < 3 """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs index 075eaf6fffa..31de2a01c62 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServer160Test.cs @@ -85,31 +85,25 @@ where l1.Id < 3 AssertSql( """ SELECT ( - SELECT TOP(1) [s].[Level3_Name] - FROM ( - SELECT TOP(1) [l4].[Id], [l4].[Level2_Required_Id], [l4].[Level3_Name], [l4].[OneToMany_Required_Inverse3Id] - FROM [Level1] AS [l0] - LEFT JOIN ( - SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] - FROM [Level1] AS [l1] - WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL - ) AS [l2] ON [l0].[Id] = CASE - WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] - END - LEFT JOIN ( - SELECT [l3].[Id], [l3].[Level2_Required_Id], [l3].[Level3_Name], [l3].[OneToMany_Required_Inverse3Id] - FROM [Level1] AS [l3] - WHERE [l3].[Level2_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse3Id] IS NOT NULL - ) AS [l4] ON CASE - WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] - END = CASE - WHEN [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [l4].[Id] - END - WHERE [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL - ) AS [s] - ORDER BY CASE - WHEN [s].[Level2_Required_Id] IS NOT NULL AND [s].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [s].[Id] - END) + SELECT TOP(1) [l4].[Level3_Name] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [l2] ON [l0].[Id] = CASE + WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] + END + LEFT JOIN ( + SELECT [l3].[Id], [l3].[Level2_Required_Id], [l3].[Level3_Name], [l3].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l3] + WHERE [l3].[Level2_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse3Id] IS NOT NULL + ) AS [l4] ON CASE + WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] + END = CASE + WHEN [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [l4].[Id] + END + WHERE [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) FROM [Level1] AS [l] WHERE [l].[Id] < 3 """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs index c6edb779d49..c2686849f93 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsSharedTypeQuerySqlServerTest.cs @@ -87,31 +87,25 @@ where l1.Id < 3 AssertSql( """ SELECT ( - SELECT TOP(1) [s].[Level3_Name] - FROM ( - SELECT TOP(1) [l4].[Id], [l4].[Level2_Required_Id], [l4].[Level3_Name], [l4].[OneToMany_Required_Inverse3Id] - FROM [Level1] AS [l0] - LEFT JOIN ( - SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] - FROM [Level1] AS [l1] - WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL - ) AS [l2] ON [l0].[Id] = CASE - WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] - END - LEFT JOIN ( - SELECT [l3].[Id], [l3].[Level2_Required_Id], [l3].[Level3_Name], [l3].[OneToMany_Required_Inverse3Id] - FROM [Level1] AS [l3] - WHERE [l3].[Level2_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse3Id] IS NOT NULL - ) AS [l4] ON CASE - WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] - END = CASE - WHEN [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [l4].[Id] - END - WHERE [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL - ) AS [s] - ORDER BY CASE - WHEN [s].[Level2_Required_Id] IS NOT NULL AND [s].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [s].[Id] - END) + SELECT TOP(1) [l4].[Level3_Name] + FROM [Level1] AS [l0] + LEFT JOIN ( + SELECT [l1].[Id], [l1].[OneToOne_Required_PK_Date], [l1].[Level1_Required_Id], [l1].[OneToMany_Required_Inverse2Id] + FROM [Level1] AS [l1] + WHERE [l1].[OneToOne_Required_PK_Date] IS NOT NULL AND [l1].[Level1_Required_Id] IS NOT NULL AND [l1].[OneToMany_Required_Inverse2Id] IS NOT NULL + ) AS [l2] ON [l0].[Id] = CASE + WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] + END + LEFT JOIN ( + SELECT [l3].[Id], [l3].[Level2_Required_Id], [l3].[Level3_Name], [l3].[OneToMany_Required_Inverse3Id] + FROM [Level1] AS [l3] + WHERE [l3].[Level2_Required_Id] IS NOT NULL AND [l3].[OneToMany_Required_Inverse3Id] IS NOT NULL + ) AS [l4] ON CASE + WHEN [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL THEN [l2].[Id] + END = CASE + WHEN [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL THEN [l4].[Id] + END + WHERE [l2].[OneToOne_Required_PK_Date] IS NOT NULL AND [l2].[Level1_Required_Id] IS NOT NULL AND [l2].[OneToMany_Required_Inverse2Id] IS NOT NULL AND [l4].[Level2_Required_Id] IS NOT NULL AND [l4].[OneToMany_Required_Inverse3Id] IS NOT NULL) FROM [Level1] AS [l] WHERE [l].[Id] < 3 """); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index 922fa23af79..acfa05fe027 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -768,6 +768,25 @@ FROM [Customers] AS [c] """); } + public override async Task Project_single_element_from_collection_with_OrderBy_Take_OrderBy_and_FirstOrDefault(bool async) + { + await base.Project_single_element_from_collection_with_OrderBy_Take_OrderBy_and_FirstOrDefault(async); + + AssertSql( + """ +SELECT [o1].[OrderID], [o1].[CustomerID], [o1].[EmployeeID], [o1].[OrderDate] +FROM [Customers] AS [c] +LEFT JOIN ( + SELECT [o0].[OrderID], [o0].[CustomerID], [o0].[EmployeeID], [o0].[OrderDate] + FROM ( + SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], ROW_NUMBER() OVER(PARTITION BY [o].[CustomerID] ORDER BY [o].[OrderID]) AS [row] + FROM [Orders] AS [o] + ) AS [o0] + WHERE [o0].[row] <= 1 +) AS [o1] ON [c].[CustomerID] = [o1].[CustomerID] +"""); + } + public override async Task Project_single_element_from_collection_with_OrderBy_Skip_and_FirstOrDefault(bool async) { await base.Project_single_element_from_collection_with_OrderBy_Skip_and_FirstOrDefault(async);