From 240357902498da01c35ea9027be6a721b99e61ee Mon Sep 17 00:00:00 2001 From: maumar Date: Thu, 24 Sep 2020 13:38:51 -0700 Subject: [PATCH] Additional regression tests for issues that have been fixed previously Resolves #10295 Resolves #12453 Resolves #13216 Resolves #13550 Resolves #13712 Resolves #13977 Resolves #15302 Resolves #17735 --- .../Query/NorthwindSelectQueryCosmosTest.cs | 53 ++++++++ .../Query/GearsOfWarQueryInMemoryTest.cs | 4 + .../TPTGearsOfWarQueryRelationalTestBase.cs | 9 ++ .../Query/ComplexNavigationsQueryTestBase.cs | 115 +++++++++++++++++ .../ComplexNavigationsWeakQueryTestBase.cs | 6 + .../Query/GearsOfWarQueryTestBase.cs | 43 +++++++ .../Query/NorthwindSelectQueryTestBase.cs | 107 ++++++++++++++++ .../ComplexNavigationsQuerySqlServerTest.cs | 117 ++++++++++++++++++ .../Query/GearsOfWarQuerySqlServerTest.cs | 30 +++++ .../NorthwindSelectQuerySqlServerTest.cs | 80 ++++++++++++ .../Query/QueryBugsTest.cs | 55 ++++++++ .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 27 ++++ 12 files changed, 646 insertions(+) diff --git a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs index 0c1be8f4be5..db1c820eb5b 100644 --- a/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindSelectQueryCosmosTest.cs @@ -1,6 +1,7 @@ // 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; using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Cosmos.Internal; @@ -1174,6 +1175,58 @@ public override Task Projecting_Length_of_a_string_property_after_FirstOrDefault return base.Projecting_Length_of_a_string_property_after_FirstOrDefault_on_correlated_collection(async); } + public override async Task Projection_take_predicate_projection(bool async) + { + await base.Projection_take_predicate_projection(async); + + AssertSql(@"@__p_0='10' + +SELECT VALUE {""Aggregate"" : ((c[""CustomerID""] || "" "") || c[""City""])} +FROM root c +WHERE ((c[""Discriminator""] = ""Customer"") AND ((c[""CustomerID""] != null) AND ((""A"" != null) AND STARTSWITH(c[""CustomerID""], ""A"")))) +ORDER BY c[""CustomerID""] +OFFSET 0 LIMIT @__p_0"); + } + + public override async Task Projection_take_projection_doesnt_project_intermittent_column(bool async) + { + await base.Projection_take_projection_doesnt_project_intermittent_column(async); + + AssertSql(@"@__p_0='10' + +SELECT VALUE {""Aggregate"" : ((c[""CustomerID""] || "" "") || c[""City""])} +FROM root c +WHERE (c[""Discriminator""] = ""Customer"") +ORDER BY c[""CustomerID""] +OFFSET 0 LIMIT @__p_0"); + } + + public override async Task Projection_skip_projection_doesnt_project_intermittent_column(bool async) + { + var message = (await Assert.ThrowsAsync( + () => base.Projection_skip_projection_doesnt_project_intermittent_column(async))).Message; + + Assert.Equal(CosmosStrings.OffsetRequiresLimit, message); + } + + [ConditionalTheory(Skip = "Issue#17246")] + public override Task Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(bool async) + { + return base.Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(async); + } + + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Projecting_count_of_navigation_which_is_generic_collection(bool async) + { + return base.Projecting_count_of_navigation_which_is_generic_collection(async); + } + + [ConditionalTheory(Skip = "Cross collection join Issue#17246")] + public override Task Projecting_count_of_navigation_which_is_generic_list(bool async) + { + return base.Projecting_count_of_navigation_which_is_generic_list(async); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs index cb2c0799ee0..663c702dcdf 100644 --- a/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/Query/GearsOfWarQueryInMemoryTest.cs @@ -72,5 +72,9 @@ public override Task Client_eval_followed_by_set_operation_throws_meaningful_exc [ConditionalTheory(Skip = "issue #17537")] public override Task SelectMany_predicate_with_non_equality_comparison_with_Take_doesnt_convert_to_join(bool async) => base.SelectMany_predicate_with_non_equality_comparison_with_Take_doesnt_convert_to_join(async); + + [ConditionalTheory(Skip = "issue #19584")] + public override Task Cast_to_derived_followed_by_include_and_FirstOrDefault(bool async) + => base.Cast_to_derived_followed_by_include_and_FirstOrDefault(async); } } diff --git a/test/EFCore.Relational.Specification.Tests/Query/TPTGearsOfWarQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/TPTGearsOfWarQueryRelationalTestBase.cs index 0ca9d91b546..4a6b80dcad4 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/TPTGearsOfWarQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/TPTGearsOfWarQueryRelationalTestBase.cs @@ -1,6 +1,9 @@ // 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.Threading.Tasks; +using Xunit; + namespace Microsoft.EntityFrameworkCore.Query { public abstract class TPTGearsOfWarQueryRelationalTestBase : GearsOfWarQueryRelationalTestBase @@ -10,5 +13,11 @@ protected TPTGearsOfWarQueryRelationalTestBase(TFixture fixture) : base(fixture) { } + + [ConditionalTheory(Skip = "issue #22691")] + public override async Task Cast_to_derived_followed_by_include_and_FirstOrDefault(bool async) + { + await base.Cast_to_derived_followed_by_include_and_FirstOrDefault(async); + } } } diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index dce7832a911..a6bdd41ad31 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -5697,5 +5697,120 @@ public virtual Task Multiple_conditionals_in_projection(bool async) } }); } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Composite_key_join_on_groupby_aggregate_projecting_only_grouping_key(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set() + .Join( + ss.Set().GroupBy(g => g.Id % 3).Select(g => new { g.Key, Sum = g.Sum(x => x.Id) }), + o => new { o.Id, Condition = true }, + i => new { Id = i.Key, Condition = i.Sum > 10, }, + (o, i) => i.Key)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Multiple_joins_groupby_predicate(bool async) + { + return AssertQuery( + async, + ss => from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id into grouping1 + from l2 in grouping1.DefaultIfEmpty() + join x in (from l3 in ss.Set() + group l3 by l3.Name into g + select new { Key = g.Key, Count = g.Count() }) on l1.Name equals x.Key into grouping2 + from x in grouping2.DefaultIfEmpty() + where l2.Name != null || x.Count > 0 + select new { l1.Id, l1.Name, Foo = l2 == null ? "Foo" : "Bar" }, + elementSorter: e => (e.Id, e.Name, e.Foo)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_FirstOrDefault_property_accesses_in_projection(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .Include(x => x.OneToMany_Optional1).ThenInclude(x => x.OneToMany_Optional2) + .Where(l1 => l1.Id < 3) + .Select(l1 => new + { + l1.Id, + Pushdown = l1.OneToMany_Optional1.Where(x => x.Name == "L2 02").FirstOrDefault().Name + })); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_FirstOrDefault_entity_reference_accesses_in_projection(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .Include(x => x.OneToMany_Optional1).ThenInclude(x => x.OneToMany_Optional2) + .Where(l1 => l1.Id < 3) + .Select(l1 => new + { + l1.Id, + Pushdown = l1.OneToMany_Optional1 + .Where(x => x.Name == "L2 02") + .FirstOrDefault().OneToOne_Optional_FK2 + })); + } + + [ConditionalTheory(Skip = "issue #22896")] + [MemberData(nameof(IsAsyncData))] + public virtual Task Collection_FirstOrDefault_entity_collection_accesses_in_projection(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .Where(l1 => l1.Id < 2) + .Select(l1 => new + { + l1.Id, + Pushdown = l1.OneToMany_Optional1 + .Where(x => x.Name == "L2 02") + .FirstOrDefault().OneToMany_Optional2.ToList() + })); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Multiple_collection_FirstOrDefault_followed_by_member_access_in_projection(bool async) + { + return AssertQuery( + async, + ss => ss.Set() + .Where(l1 => l1.Id < 2) + .Select(l1 => new + { + l1.Id, + Pushdown = l1.OneToMany_Optional1 + .Where(x => x.Name == "L2 02") + .FirstOrDefault().OneToMany_Optional2 + .OrderBy(x => x.Id) + .FirstOrDefault().Name + })); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projecting_columns_with_same_name_from_different_entities_making_sure_aliasing_works_after_Distinct(bool async) + { + return AssertQuery( + async, + ss => (from l1 in ss.Set() + join l2 in ss.Set() on l1.Id equals l2.Level1_Optional_Id + join l3 in ss.Set() on l2.Id equals l3.Level2_Optional_Id + select new { Id1 = l1.Id, Id2 = l2.Id, Id3 = l3.Id, Name1 = l1.Name, Name2 = l2.Name }).Distinct().Select(x => new { Foo = x.Id1, Bar = x.Id2, Baz = x.Id3 }).Take(10), + elementSorter: e => (e.Foo, e.Bar, e.Baz)); + } } } diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsWeakQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsWeakQueryTestBase.cs index fcb7b5ec1f8..bf277c18112 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsWeakQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsWeakQueryTestBase.cs @@ -181,5 +181,11 @@ public override void Filtered_include_outer_parameter_used_inside_filter() { // TODO: this test can be ran with weak entities once #18191 is fixed and we can use query test infra properly } + + [ConditionalTheory(Skip = "Issue#17803")] + public override Task Multiple_collection_FirstOrDefault_followed_by_member_access_in_projection(bool async) + { + return base.Multiple_collection_FirstOrDefault_followed_by_member_access_in_projection(async); + } } } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 640cce8dd04..7212769843a 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -7898,6 +7898,49 @@ await AssertQuery( ss => ss.Set().Where(ll => ll is LocustCommander && (ll as LocustCommander).HighCommandId != 0)); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Cast_to_derived_followed_by_include_and_FirstOrDefault(bool async) + { + return AssertFirstOrDefault( + async, + ss => ss.Set().Where(ll => ll.Name.Contains("Queen")).Cast().Include(lc => lc.DefeatedBy), + asserter: (e, a) => AssertInclude(e, a, new ExpectedInclude(x => x.DefeatedBy))); + + } + + [ConditionalTheory(Skip = "issue #22692")] + [MemberData(nameof(IsAsyncData))] + public virtual Task Cast_to_derived_followed_by_multiple_includes(bool async) + { + var expectedIncludes = new IExpectedInclude[] + { + new ExpectedInclude(x => x.DefeatedBy), + new ExpectedInclude(x => x.Weapons, "DefeatedBy"), + }; + + return AssertQuery( + async, + ss => ss.Set().Where(ll => ll.Name.Contains("Queen")).Cast().Include(lc => lc.DefeatedBy).ThenInclude(g => g.Weapons), + elementAsserter: (e, a) => AssertInclude(e, a, expectedIncludes)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Correlated_collection_take(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Select(g => new { g.Nickname, Weapons = g.Weapons.Take(10).ToList(), g.CityOfBirth }), + elementSorter: e => e.Nickname, + elementAsserter: (e, a) => + { + AssertEqual(e.Nickname, a.Nickname); + AssertCollection(e.Weapons, a.Weapons, elementSorter: ee => ee.Id); + AssertEqual(e.CityOfBirth, a.CityOfBirth); + }); + } + protected GearsOfWarContext CreateContext() => Fixture.CreateContext(); diff --git a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs index 1e53ec3a4de..5b1af0142be 100644 --- a/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/NorthwindSelectQueryTestBase.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Linq.Expressions; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.TestModels.Northwind; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -1860,5 +1861,111 @@ public virtual Task Projecting_Length_of_a_string_property_after_FirstOrDefault_ .Select(c => c.Orders.OrderBy(o => o.OrderID).Select(o => o.CustomerID).FirstOrDefault().MaybeScalar(x => x.Length)), assertOrder: true); } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projecting_count_of_navigation_which_is_generic_list(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Select(c => c.Orders.Count), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projecting_count_of_navigation_which_is_generic_collection(bool async) + { + var collectionCount = typeof(ICollection).GetProperty("Count"); + + var prm = Expression.Parameter(typeof(Customer), "c"); + var selector = Expression.Lambda>( + Expression.Property( + Expression.Property(prm, "Orders"), + collectionCount), + prm); + + return AssertQueryScalar( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Select(selector), + assertOrder: true); + } + + [ConditionalTheory(Skip = "issue #22701")] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projecting_count_of_navigation_which_is_generic_collection_using_convert(bool async) + { + return AssertQueryScalar( + async, + ss => ss.Set() + .OrderBy(c => c.CustomerID) + .Select(c => ((ICollection)c.Orders).Count), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projection_take_projection_doesnt_project_intermittent_column(bool async) + { + return AssertQuery( + async, + ss => ss + .Set() + .OrderBy(c => c.CustomerID) + .Select(c => new { c.CustomerID, c.City, c.CompanyName }) + .Take(10) + .Select(x => new { Aggregate = x.CustomerID + " " + x.City }), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projection_skip_projection_doesnt_project_intermittent_column(bool async) + { + return AssertQuery( + async, + ss => ss + .Set() + .OrderBy(c => c.CustomerID) + .Select(c => new { c.CustomerID, c.City, c.CompanyName }) + .Skip(7) + .Select(x => new { Aggregate = x.CustomerID + " " + x.City }), + assertOrder: true); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(bool async) + { + return AssertQuery( + async, + ss => ss + .Set() + .OrderBy(c => c.CustomerID) + .Select(c => new { c.CustomerID, FirstLetter = c.CustomerID.Substring(0, 1), Foo = "Foo" }) + .Distinct() + .Select(x => new { Aggregate = x.FirstLetter + " " + x.Foo }), + elementSorter: e => e.Aggregate); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Projection_take_predicate_projection(bool async) + { + return AssertQuery( + async, + ss => ss + .Set() + .OrderBy(c => c.CustomerID) + .Select(c => new { c.CustomerID, c.City, c.CompanyName }) + .Take(10) + .Where(x => x.CustomerID.StartsWith("A")) + .Select(x => new { Aggregate = x.CustomerID + " " + x.City }), + assertOrder: true); + } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index d3431762248..080c3545e42 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -5930,6 +5930,123 @@ FROM [LevelTwo] AS [l] LEFT JOIN [LevelOne] AS [l1] ON [l].[Level1_Optional_Id] = [l1].[Id]"); } + public override async Task Composite_key_join_on_groupby_aggregate_projecting_only_grouping_key(bool async) + { + await base.Composite_key_join_on_groupby_aggregate_projecting_only_grouping_key(async); + + AssertSql( + @"SELECT [t].[c] +FROM [LevelOne] AS [l] +INNER JOIN ( + SELECT [l0].[Id] % 3 AS [c], COALESCE(SUM([l0].[Id]), 0) AS [c0] + FROM [LevelTwo] AS [l0] + GROUP BY [l0].[Id] % 3 +) AS [t] ON ([l].[Id] = [t].[c]) AND (CAST(1 AS bit) = CASE + WHEN [t].[c0] > 10 THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END)"); + } + + public override async Task Multiple_joins_groupby_predicate(bool async) + { + await base.Multiple_joins_groupby_predicate(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Name], CASE + WHEN [l0].[Id] IS NULL THEN N'Foo' + ELSE N'Bar' +END AS [Foo] +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] +LEFT JOIN ( + SELECT [l1].[Name], COUNT(*) AS [c] + FROM [LevelThree] AS [l1] + GROUP BY [l1].[Name] +) AS [t] ON [l].[Name] = [t].[Name] +WHERE [l0].[Name] IS NOT NULL OR ([t].[c] > 0)"); + } + + public override async Task Collection_FirstOrDefault_property_accesses_in_projection(bool async) + { + await base.Collection_FirstOrDefault_property_accesses_in_projection(async); + + AssertSql( + @"SELECT [l0].[Id], ( + SELECT TOP(1) [l].[Name] + FROM [LevelTwo] AS [l] + WHERE ([l0].[Id] = [l].[OneToMany_Optional_Inverse2Id]) AND ([l].[Name] = N'L2 02')) AS [Pushdown] +FROM [LevelOne] AS [l0] +WHERE [l0].[Id] < 3"); + } + + public override async Task Collection_FirstOrDefault_entity_reference_accesses_in_projection(bool async) + { + await base.Collection_FirstOrDefault_entity_reference_accesses_in_projection(async); + + AssertSql( + @"SELECT [l].[Id], [t0].[Id], [t0].[Level2_Optional_Id], [t0].[Level2_Required_Id], [t0].[Name], [t0].[OneToMany_Optional_Inverse3Id], [t0].[OneToMany_Optional_Self_Inverse3Id], [t0].[OneToMany_Required_Inverse3Id], [t0].[OneToMany_Required_Self_Inverse3Id], [t0].[OneToOne_Optional_PK_Inverse3Id], [t0].[OneToOne_Optional_Self3Id] +FROM [LevelOne] AS [l] +LEFT JOIN ( + SELECT [t].[Id], [t].[Level2_Optional_Id], [t].[Level2_Required_Id], [t].[Name], [t].[OneToMany_Optional_Inverse3Id], [t].[OneToMany_Optional_Self_Inverse3Id], [t].[OneToMany_Required_Inverse3Id], [t].[OneToMany_Required_Self_Inverse3Id], [t].[OneToOne_Optional_PK_Inverse3Id], [t].[OneToOne_Optional_Self3Id], [t].[OneToMany_Optional_Inverse2Id] + FROM ( + SELECT [l1].[Id], [l1].[Level2_Optional_Id], [l1].[Level2_Required_Id], [l1].[Name], [l1].[OneToMany_Optional_Inverse3Id], [l1].[OneToMany_Optional_Self_Inverse3Id], [l1].[OneToMany_Required_Inverse3Id], [l1].[OneToMany_Required_Self_Inverse3Id], [l1].[OneToOne_Optional_PK_Inverse3Id], [l1].[OneToOne_Optional_Self3Id], [l0].[OneToMany_Optional_Inverse2Id], ROW_NUMBER() OVER(PARTITION BY [l0].[OneToMany_Optional_Inverse2Id] ORDER BY [l0].[Id], [l1].[Id]) AS [row] + FROM [LevelTwo] AS [l0] + LEFT JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Optional_Id] + WHERE [l0].[Name] = N'L2 02' + ) AS [t] + WHERE [t].[row] <= 1 +) AS [t0] ON [l].[Id] = [t0].[OneToMany_Optional_Inverse2Id] +WHERE [l].[Id] < 3"); + } + + public override async Task Collection_FirstOrDefault_entity_collection_accesses_in_projection(bool async) + { + await base.Collection_FirstOrDefault_entity_collection_accesses_in_projection(async); + + AssertSql( + @""); + } + + public override async Task Multiple_collection_FirstOrDefault_followed_by_member_access_in_projection(bool async) + { + await base.Multiple_collection_FirstOrDefault_followed_by_member_access_in_projection(async); + + AssertSql( + @"SELECT [l2].[Id], ( + SELECT TOP(1) [l].[Name] + FROM [LevelThree] AS [l] + WHERE ( + SELECT TOP(1) [l0].[Id] + FROM [LevelTwo] AS [l0] + WHERE ([l2].[Id] = [l0].[OneToMany_Optional_Inverse2Id]) AND ([l0].[Name] = N'L2 02')) IS NOT NULL AND ((( + SELECT TOP(1) [l1].[Id] + FROM [LevelTwo] AS [l1] + WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND ([l1].[Name] = N'L2 02')) = [l].[OneToMany_Optional_Inverse3Id]) OR (( + SELECT TOP(1) [l1].[Id] + FROM [LevelTwo] AS [l1] + WHERE ([l2].[Id] = [l1].[OneToMany_Optional_Inverse2Id]) AND ([l1].[Name] = N'L2 02')) IS NULL AND [l].[OneToMany_Optional_Inverse3Id] IS NULL)) + ORDER BY [l].[Id]) AS [Pushdown] +FROM [LevelOne] AS [l2] +WHERE [l2].[Id] < 2"); + } + + public override async Task Projecting_columns_with_same_name_from_different_entities_making_sure_aliasing_works_after_Distinct(bool async) + { + await base.Projecting_columns_with_same_name_from_different_entities_making_sure_aliasing_works_after_Distinct(async); + + // see #22915 + AssertSql( + @"@__p_0='10' + +SELECT [t].[Id] AS [Foo], [t].[Id0] AS [Bar], [t].[Id1] AS [Baz] +FROM ( + SELECT DISTINCT TOP(@__p_0) [l].[Id], [l0].[Id] AS [Id0], [l1].[Id] AS [Id1], [l].[Name], [l0].[Name] AS [Name0] + FROM [LevelOne] AS [l] + INNER JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] + INNER JOIN [LevelThree] AS [l1] ON [l0].[Id] = [l1].[Level2_Optional_Id] +) AS [t]"); + } + 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 b8371c724e8..9a06398a5e1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -7189,6 +7189,36 @@ FROM [LocustLeaders] AS [l] WHERE ([l].[Discriminator] = N'LocustCommander') AND (([l].[HighCommandId] <> 0) OR [l].[HighCommandId] IS NULL)"); } + public override async Task Cast_to_derived_followed_by_include_and_FirstOrDefault(bool async) + { + await base.Cast_to_derived_followed_by_include_and_FirstOrDefault(async); + + AssertSql( + @"SELECT TOP(1) [l].[Name], [l].[Discriminator], [l].[LocustHordeId], [l].[ThreatLevel], [l].[ThreatLevelByte], [l].[ThreatLevelNullableByte], [l].[DefeatedByNickname], [l].[DefeatedBySquadId], [l].[HighCommandId], [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [LocustLeaders] AS [l] +LEFT JOIN [Gears] AS [g] ON ([l].[DefeatedByNickname] = [g].[Nickname]) AND ([l].[DefeatedBySquadId] = [g].[SquadId]) +WHERE [l].[Name] LIKE N'%Queen%'"); + } + + public override async Task Correlated_collection_take(bool async) + { + await base.Correlated_collection_take(async); + + AssertSql( + @"SELECT [g].[Nickname], [c].[Name], [c].[Location], [c].[Nation], [g].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId] +FROM [Gears] AS [g] +INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] +LEFT JOIN ( + SELECT [t].[Id], [t].[AmmunitionType], [t].[IsAutomatic], [t].[Name], [t].[OwnerFullName], [t].[SynergyWithId] + FROM ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], ROW_NUMBER() OVER(PARTITION BY [w].[OwnerFullName] ORDER BY [w].[Id]) AS [row] + FROM [Weapons] AS [w] + ) AS [t] + WHERE [t].[row] <= 10 +) AS [t0] ON [g].[FullName] = [t0].[OwnerFullName] +ORDER BY [g].[Nickname], [g].[SquadId], [c].[Name], [t0].[OwnerFullName], [t0].[Id]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs index cc08beb5b9d..3f869aa6f90 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NorthwindSelectQuerySqlServerTest.cs @@ -1464,6 +1464,86 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID]"); } + public override async Task Projecting_count_of_navigation_which_is_generic_list(bool async) + { + await base.Projecting_count_of_navigation_which_is_generic_list(async); + + AssertSql( + @"SELECT ( + SELECT COUNT(*) + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID]) +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]"); + } + + public override async Task Projecting_count_of_navigation_which_is_generic_collection(bool async) + { + await base.Projecting_count_of_navigation_which_is_generic_collection(async); + + AssertSql( + @"SELECT ( + SELECT COUNT(*) + FROM [Orders] AS [o] + WHERE [c].[CustomerID] = [o].[CustomerID]) +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]"); + } + + public override async Task Projection_take_projection_doesnt_project_intermittent_column(bool async) + { + await base.Projection_take_projection_doesnt_project_intermittent_column(async); + + AssertSql( + @"@__p_0='10' + +SELECT TOP(@__p_0) ([c].[CustomerID] + N' ') + COALESCE([c].[City], N'') AS [Aggregate] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID]"); + } + + public override async Task Projection_skip_projection_doesnt_project_intermittent_column(bool async) + { + await base.Projection_skip_projection_doesnt_project_intermittent_column(async); + + AssertSql( + @"@__p_0='7' + +SELECT ([c].[CustomerID] + N' ') + COALESCE([c].[City], N'') AS [Aggregate] +FROM [Customers] AS [c] +ORDER BY [c].[CustomerID] +OFFSET @__p_0 ROWS"); + } + + public override async Task Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(bool async) + { + await base.Projection_Distinct_projection_preserves_columns_used_for_distinct_in_subquery(async); + + AssertSql( + @"SELECT (COALESCE([t].[c], N'') + N' ') + [t].[c0] AS [Aggregate] +FROM ( + SELECT DISTINCT [c].[CustomerID], SUBSTRING([c].[CustomerID], 0 + 1, 1) AS [c], N'Foo' AS [c0] + FROM [Customers] AS [c] +) AS [t]"); + } + + public override async Task Projection_take_predicate_projection(bool async) + { + await base.Projection_take_predicate_projection(async); + + AssertSql( + @"@__p_0='10' + +SELECT ([t].[CustomerID] + N' ') + COALESCE([t].[City], N'') AS [Aggregate] +FROM ( + SELECT TOP(@__p_0) [c].[CustomerID], [c].[City] + FROM [Customers] AS [c] + ORDER BY [c].[CustomerID] +) AS [t] +WHERE [t].[CustomerID] LIKE N'A%' +ORDER BY [t].[CustomerID]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs index 0e751fc110e..2957117ad8d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/QueryBugsTest.cs @@ -9301,6 +9301,61 @@ private SqlServerTestStore CreateDatabase11835() #endregion + #region Issue10295 + + [ConditionalFact] + public virtual void Query_filter_with_contains_evaluates_correctly() + { + using (CreateDatabase10295()) + { + using var context = new MyContext10295(_options); + var result = context.Entities.ToList(); + Assert.Equal(1, result.Count); + + AssertSql( + @"SELECT [e].[Id], [e].[Name] +FROM [Entities] AS [e] +WHERE [e].[Id] NOT IN (1, 7)"); + } + } + + public class MyContext10295 : DbContext + { + private readonly List _ids = new List { 1, 7 }; + + public DbSet Entities { get; set; } + + public MyContext10295(DbContextOptions options) + : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasQueryFilter(x => !_ids.Contains(x.Id)); + } + } + + public class MyEntity10295 + { + public int Id { get; set; } + public string Name { get; set; } + } + + private SqlServerTestStore CreateDatabase10295() + => CreateTestStore( + () => new MyContext10295(_options), + context => + { + var e1 = new MyEntity10295 { Name = "Name1" }; + var e2 = new MyEntity10295 { Name = "Name2" }; + context.Entities.AddRange(e1, e2); + context.SaveChanges(); + ClearLog(); + }); + + #endregion + private DbContextOptions _options; private SqlServerTestStore CreateTestStore( diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index d84af311e1d..c73f397ff5b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -8342,6 +8342,33 @@ FROM [LocustLeaders] AS [l] WHERE [l0].[Name] IS NOT NULL AND (([l0].[HighCommandId] <> 0) OR [l0].[HighCommandId] IS NULL)"); } + public override async Task Cast_to_derived_followed_by_include_and_FirstOrDefault(bool async) + { + await base.Cast_to_derived_followed_by_include_and_FirstOrDefault(async); + + AssertSql( + @""); + } + + public override async Task Correlated_collection_take(bool async) + { + await base.Correlated_collection_take(async); + + AssertSql( + @"SELECT [g].[Nickname], [c].[Name], [c].[Location], [c].[Nation], [g].[SquadId], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId] +FROM [Gears] AS [g] +INNER JOIN [Cities] AS [c] ON [g].[CityOfBirthName] = [c].[Name] +LEFT JOIN ( + SELECT [t].[Id], [t].[AmmunitionType], [t].[IsAutomatic], [t].[Name], [t].[OwnerFullName], [t].[SynergyWithId] + FROM ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], ROW_NUMBER() OVER(PARTITION BY [w].[OwnerFullName] ORDER BY [w].[Id]) AS [row] + FROM [Weapons] AS [w] + ) AS [t] + WHERE [t].[row] <= 10 +) AS [t0] ON [g].[FullName] = [t0].[OwnerFullName] +ORDER BY [g].[Nickname], [g].[SquadId], [c].[Name], [t0].[OwnerFullName], [t0].[Id]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }