From 10b819560dfb4e2870ef81de9d191bfafba5a1cd Mon Sep 17 00:00:00 2001 From: maumar Date: Fri, 29 May 2020 01:45:54 -0700 Subject: [PATCH] Adding regression tests for #12826 - Query: Incorrect syntax near the keyword 'AS` for group by aggregate Resolves #12826 --- .../Query/ComplexNavigationsQueryTestBase.cs | 55 ++++++ .../Query/GearsOfWarQueryTestBase.cs | 13 ++ .../Query/NorthwindGroupByQueryTestBase.cs | 158 ++++++++++++++++++ .../ComplexNavigationsQuerySqlServerTest.cs | 26 +++ .../Query/GearsOfWarQuerySqlServerTest.cs | 13 ++ .../NorthwindGroupByQuerySqlServerTest.cs | 104 ++++++++++++ 6 files changed, 369 insertions(+) diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index 70c02eb76eb..1389e7be711 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -5416,5 +5416,60 @@ public virtual async Task Filtered_include_calling_methods_directly_on_parameter .Include(l1 => l1.OneToMany_Optional1) .ThenInclude(l2 => l2.AsQueryable().Where(xx => xx.Id != 42))))).Message; } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Element_selector_with_coalesce_repeated_in_aggregate(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set().GroupBy( + l1 => l1.OneToOne_Required_PK1.OneToOne_Required_PK2.Name, + l1 => new + { + Id = ((int?)l1.OneToOne_Required_PK1.Id ?? 0) + }) + .Where(g => g.Min(l1 => l1.Id + l1.Id) > 0) + .Select(g => g.Count())); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Nested_object_constructed_from_group_key_properties(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .Where(l1 => l1.OneToOne_Optional_FK1 != null) + .GroupBy(l1 => new + { + l1.Id, + l1.Date, + l1.Name, + InnerId = l1.OneToOne_Optional_FK1.Id, + InnerDate = l1.OneToOne_Optional_FK1.Date, + InnerOptionalId = l1.OneToOne_Optional_FK1.Level1_Optional_Id, + InnerRequiredId = l1.OneToOne_Optional_FK1.Level1_Required_Id, + InnerName = l1.OneToOne_Required_FK1.Name + }) + .Select(g => new + { + NestedEntity = new Level1 + { + Id = g.Key.Id, + Name = g.Key.Name, + Date = g.Key.Date, + OneToOne_Optional_FK1 = new Level2 + { + Id = g.Key.InnerId, + Name = g.Key.InnerName, + Date = g.Key.InnerDate, + Level1_Optional_Id = g.Key.InnerOptionalId, + Level1_Required_Id = g.Key.InnerRequiredId + } + }, + Aggregate = g.Sum(x => x.Name.Length) + })); + } } } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index a1be2007b69..cade2033b6d 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -7574,6 +7574,19 @@ public virtual Task Coalesce_used_with_non_unicode_string_column_and_constant(bo ss => ss.Set().Select(c => c.Location ?? "Unknown")); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Groupby_anonymous_type_with_navigations_followed_up_by_anonymous_projection_and_orderby(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .GroupBy(w => new { w.Owner.CityOfBirth.Name, w.Owner.CityOfBirth.Location }) + .Select(x => new { x.Key.Name, x.Key.Location, Count = x.Count() }) + .OrderBy(x => x.Location), + assertOrder: true); + } + protected GearsOfWarContext CreateContext() => Fixture.CreateContext(); protected virtual void ClearLog() diff --git a/test/EFCore.Specification.Tests/Query/NorthwindGroupByQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindGroupByQueryTestBase.cs index c4408de473d..8e6d07c6a2d 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindGroupByQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindGroupByQueryTestBase.cs @@ -363,6 +363,73 @@ public virtual Task Group_by_with_arithmetic_operation_inside_aggregate(bool asy }); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Group_by_with_projection_into_DTO(bool async) + { + return AssertQuery( + async, + ss => ss.Set().GroupBy(o => o.OrderID).Select(x => new LongIntDto { Id = x.Key, Count = x.Count() }), + elementSorter: e => e.Id, + elementAsserter: (e, a) => + { + Assert.Equal(e.Id, a.Id); + Assert.Equal(e.Count, a.Count); + }); + } + + private class LongIntDto + { + public long Id { get; set; } + public int Count { get; set; } + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual async Task Where_select_function_groupby_followed_by_another_select_with_aggregates(bool async) + { + await AssertQuery( + async, + ss => ss.Set() + .Where(o => o.CustomerID.StartsWith("A")) + .Select(o => new { o.CustomerID, Age = 2020 - o.OrderDate.Value.Year, o.OrderID }) + .GroupBy(x => x.CustomerID) + .Select(x => new + { + x.Key, + Sum1 = x.Sum(y => y.Age <= 30 ? y.OrderID : 0), + Sum2 = x.Sum(y => y.Age > 30 && y.Age <= 60 ? y.OrderID : 0) + })); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Group_by_column_project_constant(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set().GroupBy(o => o.CustomerID).OrderBy(g => g.Key).Select(e => 42)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Key_plus_key_in_projection(bool async) + { + return AssertQuery( + async, + ss => (from o in ss.Set() + join c in ss.Set() on o.CustomerID equals c.CustomerID into grouping + from c in grouping.DefaultIfEmpty() + select o) + .GroupBy(o => o.OrderID) + .Select( + g => new + { + Value = g.Key + g.Key, + Average = g.Average(o => o.OrderID) + })); + } + #endregion #region GroupByAnonymousAggregate @@ -998,6 +1065,19 @@ public virtual Task GroupBy_based_on_renamed_property_complex(bool async) elementSorter: e => e.Key); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Join_groupby_anonymous_orderby_anonymous_projection(bool async) + { + return AssertQuery( + async, + ss => from c in ss.Set() + join o in ss.Set() on c.CustomerID equals o.CustomerID + group new { c, o } by new { c.CustomerID, o.OrderDate } into grouping + orderby grouping.Key.OrderDate + select new { grouping.Key.CustomerID, grouping.Key.OrderDate }); + } + #endregion #region GroupByWithElementSelectorAggregate @@ -1193,6 +1273,30 @@ public virtual Task GroupBy_element_selector_complex_aggregate4(bool async) .Select(g => g.Sum(e => e))); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Element_selector_with_case_block_repeated_inside_another_case_block_in_projection(bool async) + { + return AssertQuery( + async, + ss => from order in ss.Set() + group new + { + IsAlfki = order.CustomerID == "ALFKI", + OrderId = order.OrderID > 1000 ? order.OrderID : -order.OrderID + } by + new + { + order.OrderID + } + into g + select new + { + g.Key.OrderID, + Aggregate = g.Sum(s => s.IsAlfki ? s.OrderId : -s.OrderId) + }); + } + #endregion #region GroupByAfterComposition @@ -1538,6 +1642,25 @@ public virtual Task GroupBy_principal_key_property_optimization(bool async) g => new { g.Key, Count = g.Count() })); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupBy_after_anonymous_projection_and_distinct_followed_by_another_anonymous_projection(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .Select(o => new { o.CustomerID, o.OrderID }) + .Distinct() + .GroupBy(x => new { x.CustomerID }) + .Select(g => new { Key = g.Key.CustomerID, Count = g.Count() }), + elementSorter: e => (e.Key, e.Count), + elementAsserter: (e, a) => + { + Assert.Equal(e.Key, a.Key); + Assert.Equal(e.Count, a.Count); + }); + } + #endregion #region GroupByAggregateComposition @@ -2008,6 +2131,41 @@ public virtual Task GroupBy_Property_Select_LongCount_with_predicate(bool async) ss => ss.Set().GroupBy(o => o.CustomerID).Select(g => g.LongCount(o => o.OrderID < 10300))); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupBy_orderby_projection_with_coalesce_operation(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .GroupBy(c => c.City) + .OrderByDescending(x => x.Count()) + .ThenBy(x => x.Key) + .Select(x => new + { + Locality = x.Key ?? "Unknown", + Count = x.Count() + })); + } + + [ConditionalTheory(Skip = "issue #18923")] + [MemberData(nameof(IsAsyncData))] + public virtual Task GroupBy_let_orderby_projection_with_coalesce_operation(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .GroupBy(c => c.City) + .Select(g => new { citiesCount = g.Count(), g }) + .OrderByDescending(x => x.citiesCount) + .ThenBy(x => x.g.Key) + .Select(x => new + { + Locality = x.g.Key ?? "Unknown", + Count = x.citiesCount + })); + } + #endregion #region GroupByWithoutAggregate diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 897559b3d3e..6d6011470a6 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -5697,6 +5697,32 @@ public override void Filtered_include_outer_parameter_used_inside_filter_split() AssertSql(" "); } + public override async Task Element_selector_with_coalesce_repeated_in_aggregate(bool async) + { + await base.Element_selector_with_coalesce_repeated_in_aggregate(async); + + AssertSql( + @"SELECT COUNT(*) +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Id] +LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Id] +GROUP BY [l1].[Name] +HAVING MIN(COALESCE([l0].[Id], 0) + COALESCE([l0].[Id], 0)) > 0"); + } + + public override async Task Nested_object_constructed_from_group_key_properties(bool async) + { + await base.Nested_object_constructed_from_group_key_properties(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Name], [l].[Date], [l0].[Id], [l1].[Name], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], COALESCE(SUM(CAST(LEN([l].[Name]) AS int)), 0) AS [Aggregate] +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] +LEFT JOIN [LevelTwo] AS [l1] ON [l].[Id] = [l1].[Level1_Required_Id] +WHERE [l0].[Id] IS NOT NULL +GROUP BY [l].[Id], [l].[Date], [l].[Name], [l0].[Id], [l0].[Date], [l0].[Level1_Optional_Id], [l0].[Level1_Required_Id], [l1].[Name]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 090878c8e40..10c83009860 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -6979,6 +6979,19 @@ public override async Task Coalesce_used_with_non_unicode_string_column_and_cons FROM [Cities] AS [c]"); } + public override async Task Groupby_anonymous_type_with_navigations_followed_up_by_anonymous_projection_and_orderby(bool async) + { + await base.Groupby_anonymous_type_with_navigations_followed_up_by_anonymous_projection_and_orderby(async); + + AssertSql( + @"SELECT [c].[Name], [c].[Location], COUNT(*) AS [Count] +FROM [Weapons] AS [w] +LEFT JOIN [Gears] AS [g] ON [w].[OwnerFullName] = [g].[FullName] +LEFT JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] +GROUP BY [c].[Name], [c].[Location] +ORDER BY [c].[Location]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindGroupByQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindGroupByQuerySqlServerTest.cs index e6c6affd5f7..ea4ab0f54f0 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindGroupByQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindGroupByQuerySqlServerTest.cs @@ -809,6 +809,25 @@ FROM [Orders] AS [o] GROUP BY [o].[CustomerID]"); } + public override async Task Element_selector_with_case_block_repeated_inside_another_case_block_in_projection(bool async) + { + await base.Element_selector_with_case_block_repeated_inside_another_case_block_in_projection(async); + + AssertSql( + @"SELECT [o].[OrderID], COALESCE(SUM(CASE + WHEN [o].[CustomerID] = N'ALFKI' THEN CASE + WHEN [o].[OrderID] > 1000 THEN [o].[OrderID] + ELSE -[o].[OrderID] + END + ELSE -CASE + WHEN [o].[OrderID] > 1000 THEN [o].[OrderID] + ELSE -[o].[OrderID] + END +END), 0) AS [Aggregate] +FROM [Orders] AS [o] +GROUP BY [o].[OrderID]"); + } + public override async Task GroupBy_empty_key_Aggregate(bool async) { await base.GroupBy_empty_key_Aggregate(async); @@ -1131,6 +1150,19 @@ FROM [Orders] AS [o] GROUP BY [c].[CustomerID]"); } + public override async Task GroupBy_after_anonymous_projection_and_distinct_followed_by_another_anonymous_projection(bool async) + { + await base.GroupBy_after_anonymous_projection_and_distinct_followed_by_another_anonymous_projection(async); + + AssertSql( + @"SELECT [t].[CustomerID] AS [Key], COUNT(*) AS [Count] +FROM ( + SELECT DISTINCT [o].[CustomerID], [o].[OrderID] + FROM [Orders] AS [o] +) AS [t] +GROUP BY [t].[CustomerID]"); + } + public override async Task GroupBy_OrderBy_key(bool async) { await base.GroupBy_OrderBy_key(async); @@ -1747,6 +1779,18 @@ FROM [Customers] AS [c] GROUP BY [t].[City]"); } + public override async Task Join_groupby_anonymous_orderby_anonymous_projection(bool async) + { + await base.Join_groupby_anonymous_orderby_anonymous_projection(async); + + AssertSql( + @"SELECT [c].[CustomerID], [o].[OrderDate] +FROM [Customers] AS [c] +INNER JOIN [Orders] AS [o] ON [c].[CustomerID] = [o].[CustomerID] +GROUP BY [c].[CustomerID], [o].[OrderDate] +ORDER BY [o].[OrderDate]"); + } + public override async Task GroupBy_with_group_key_access_thru_navigation(bool async) { await base.GroupBy_with_group_key_access_thru_navigation(async); @@ -1831,6 +1875,17 @@ public override Task GroupBy_Property_Select_LongCount_with_predicate(bool async () => base.GroupBy_Property_Select_LongCount_with_predicate(async)); } + public override async Task GroupBy_orderby_projection_with_coalesce_operation(bool async) + { + await base.GroupBy_orderby_projection_with_coalesce_operation(async); + + AssertSql( + @"SELECT COALESCE([c].[City], N'Unknown') AS [Locality], COUNT(*) AS [Count] +FROM [Customers] AS [c] +GROUP BY [c].[City] +ORDER BY COUNT(*) DESC, [c].[City]"); + } + public override async Task GroupBy_with_grouping_key_using_Like(bool async) { await base.GroupBy_with_grouping_key_using_Like(async); @@ -1891,6 +1946,55 @@ public override async Task Complex_query_with_groupBy_in_subquery3(bool async) @""); } + public override async Task Group_by_with_projection_into_DTO(bool async) + { + await base.Group_by_with_projection_into_DTO(async); + + AssertSql( + @"SELECT CAST([o].[OrderID] AS bigint) AS [Id], COUNT(*) AS [Count] +FROM [Orders] AS [o] +GROUP BY [o].[OrderID]"); + } + + public override async Task Where_select_function_groupby_followed_by_another_select_with_aggregates(bool async) + { + await base.Where_select_function_groupby_followed_by_another_select_with_aggregates(async); + + AssertSql( + @"SELECT [o].[CustomerID] AS [Key], COALESCE(SUM(CASE + WHEN (2020 - DATEPART(year, [o].[OrderDate])) <= 30 THEN [o].[OrderID] + ELSE 0 +END), 0) AS [Sum1], COALESCE(SUM(CASE + WHEN ((2020 - DATEPART(year, [o].[OrderDate])) > 30) AND ((2020 - DATEPART(year, [o].[OrderDate])) <= 60) THEN [o].[OrderID] + ELSE 0 +END), 0) AS [Sum2] +FROM [Orders] AS [o] +WHERE [o].[CustomerID] IS NOT NULL AND ([o].[CustomerID] LIKE N'A%') +GROUP BY [o].[CustomerID]"); + } + + public override async Task Group_by_column_project_constant(bool async) + { + await base.Group_by_column_project_constant(async); + + AssertSql( + @"SELECT 42 +FROM [Orders] AS [o] +GROUP BY [o].[CustomerID] +ORDER BY [o].[CustomerID]"); + } + + public override async Task Key_plus_key_in_projection(bool async) + { + await base.Key_plus_key_in_projection(async); + + AssertSql( + @"SELECT [o].[OrderID] + [o].[OrderID] AS [Value], AVG(CAST([o].[OrderID] AS float)) AS [Average] +FROM [Orders] AS [o] +LEFT JOIN [Customers] AS [c] ON [o].[CustomerID] = [c].[CustomerID] +GROUP BY [o].[OrderID]"); + } + public override async Task Complex_query_with_groupBy_in_subquery4(bool async) { await base.Complex_query_with_groupBy_in_subquery4(async);