From b63494d6273d1278e71d69ec270721ee78d2bf73 Mon Sep 17 00:00:00 2001 From: maumar Date: Mon, 14 Dec 2020 16:03:28 -0800 Subject: [PATCH] add regression tests for #23674 --- .../Query/ComplexNavigationsQueryTestBase.cs | 11 ++++++++ .../Query/GearsOfWarQueryTestBase.cs | 21 ++++++++++++++++ .../ComplexNavigationsQuerySqlServerTest.cs | 16 ++++++++++++ .../Query/GearsOfWarQuerySqlServerTest.cs | 16 ++++++++++++ .../Query/TPTGearsOfWarQuerySqlServerTest.cs | 25 +++++++++++++++++++ 5 files changed, 89 insertions(+) diff --git a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs index 380c20bfdca..0a3cd9a05d4 100644 --- a/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/ComplexNavigationsQueryTestBase.cs @@ -5878,5 +5878,16 @@ select innerL1s.ToList()).FirstOrDefault() assertOrder: true, elementAsserter: (e, a) => AssertCollection(e, a)); } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(bool async) + { + return AssertQuery( + async, + ss => ss.Set().AsTracking() + .Include(l2 => l2.OneToMany_Optional2) + .ThenInclude(l3 => l3.OneToMany_Optional_Inverse3.OneToMany_Required2)); + } } } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index 54cb2581035..55ff5127fe9 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -7954,6 +7954,27 @@ public virtual Task Array_access_on_byte_array(bool async) ss => ss.Set().Where(e => e.Banner5[2] == 0x06)); } + [ConditionalTheory(Skip = "issue #23674")] + [MemberData(nameof(IsAsyncData))] + public virtual Task Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(bool async) + { + var expectedIncludes = new IExpectedInclude[] + { + new ExpectedInclude(e => e.Weapons), + new ExpectedInclude(e => e.Owner, "Weapons"), + new ExpectedInclude(e => e.AssignedCity, "Weapons.Owner") + }; + + return AssertQuery( + async, + ss => ss.Set() + .AsTracking() + .Include(g => g.Weapons) + .ThenInclude(w => w.Owner.AssignedCity), + elementAsserter: (e, a) => AssertInclude(e, a, expectedIncludes), + entryCount: 17); + } + protected GearsOfWarContext CreateContext() => Fixture.CreateContext(); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index 54c46d13287..94b5e40152d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -6073,6 +6073,22 @@ SELECT 1 ORDER BY [l].[Id], [t0].[Id], [t1].[Id]"); } + public override async Task Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(bool async) + { + await base.Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(async); + + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Level1_Optional_Id], [l].[Level1_Required_Id], [l].[Name], [l].[OneToMany_Optional_Inverse2Id], [l].[OneToMany_Optional_Self_Inverse2Id], [l].[OneToMany_Required_Inverse2Id], [l].[OneToMany_Required_Self_Inverse2Id], [l].[OneToOne_Optional_PK_Inverse2Id], [l].[OneToOne_Optional_Self2Id], [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].[Id0], [t].[Date], [t].[Level1_Optional_Id], [t].[Level1_Required_Id], [t].[Name0], [t].[OneToMany_Optional_Inverse2Id], [t].[OneToMany_Optional_Self_Inverse2Id], [t].[OneToMany_Required_Inverse2Id], [t].[OneToMany_Required_Self_Inverse2Id], [t].[OneToOne_Optional_PK_Inverse2Id], [t].[OneToOne_Optional_Self2Id], [t].[Id1], [t].[Level2_Optional_Id0], [t].[Level2_Required_Id0], [t].[Name1], [t].[OneToMany_Optional_Inverse3Id0], [t].[OneToMany_Optional_Self_Inverse3Id0], [t].[OneToMany_Required_Inverse3Id0], [t].[OneToMany_Required_Self_Inverse3Id0], [t].[OneToOne_Optional_PK_Inverse3Id0], [t].[OneToOne_Optional_Self3Id0] +FROM [LevelTwo] AS [l] +LEFT JOIN ( + SELECT [l0].[Id], [l0].[Level2_Optional_Id], [l0].[Level2_Required_Id], [l0].[Name], [l0].[OneToMany_Optional_Inverse3Id], [l0].[OneToMany_Optional_Self_Inverse3Id], [l0].[OneToMany_Required_Inverse3Id], [l0].[OneToMany_Required_Self_Inverse3Id], [l0].[OneToOne_Optional_PK_Inverse3Id], [l0].[OneToOne_Optional_Self3Id], [l1].[Id] AS [Id0], [l1].[Date], [l1].[Level1_Optional_Id], [l1].[Level1_Required_Id], [l1].[Name] AS [Name0], [l1].[OneToMany_Optional_Inverse2Id], [l1].[OneToMany_Optional_Self_Inverse2Id], [l1].[OneToMany_Required_Inverse2Id], [l1].[OneToMany_Required_Self_Inverse2Id], [l1].[OneToOne_Optional_PK_Inverse2Id], [l1].[OneToOne_Optional_Self2Id], [l2].[Id] AS [Id1], [l2].[Level2_Optional_Id] AS [Level2_Optional_Id0], [l2].[Level2_Required_Id] AS [Level2_Required_Id0], [l2].[Name] AS [Name1], [l2].[OneToMany_Optional_Inverse3Id] AS [OneToMany_Optional_Inverse3Id0], [l2].[OneToMany_Optional_Self_Inverse3Id] AS [OneToMany_Optional_Self_Inverse3Id0], [l2].[OneToMany_Required_Inverse3Id] AS [OneToMany_Required_Inverse3Id0], [l2].[OneToMany_Required_Self_Inverse3Id] AS [OneToMany_Required_Self_Inverse3Id0], [l2].[OneToOne_Optional_PK_Inverse3Id] AS [OneToOne_Optional_PK_Inverse3Id0], [l2].[OneToOne_Optional_Self3Id] AS [OneToOne_Optional_Self3Id0] + FROM [LevelThree] AS [l0] + LEFT JOIN [LevelTwo] AS [l1] ON [l0].[OneToMany_Optional_Inverse3Id] = [l1].[Id] + LEFT JOIN [LevelThree] AS [l2] ON [l1].[Id] = [l2].[OneToMany_Required_Inverse3Id] +) AS [t] ON [l].[Id] = [t].[OneToMany_Optional_Inverse3Id] +ORDER BY [l].[Id], [t].[Id], [t].[Id0], [t].[Id1]"); + } + 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 4d6a7589cea..11743bea3b1 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -7364,6 +7364,22 @@ public override async Task Array_access_on_byte_array(bool async) WHERE CAST(SUBSTRING([s].[Banner5], 2 + 1, 1) AS tinyint) = CAST(6 AS tinyint)"); } + public override async Task Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(bool async) + { + await base.Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(async); + + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], [t].[Id], [t].[AmmunitionType], [t].[IsAutomatic], [t].[Name], [t].[OwnerFullName], [t].[SynergyWithId], [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[Discriminator], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [t].[Name0], [t].[Location], [t].[Nation] +FROM [Gears] AS [g] +LEFT JOIN ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[Discriminator], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], [c].[Name] AS [Name0], [c].[Location], [c].[Nation] + FROM [Weapons] AS [w] + LEFT JOIN [Gears] AS [g0] ON [w].[OwnerFullName] = [g0].[FullName] + LEFT JOIN [Cities] AS [c] ON [g0].[AssignedCityName] = [c].[Name] +) AS [t] ON [g].[FullName] = [t].[OwnerFullName] +ORDER BY [g].[Nickname], [g].[SquadId], [t].[Id], [t].[Nickname], [t].[SquadId], [t].[Name0]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs index 9a593b71c22..9bc19d9c108 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/TPTGearsOfWarQuerySqlServerTest.cs @@ -8514,6 +8514,31 @@ public override async Task Array_access_on_byte_array(bool async) WHERE CAST(SUBSTRING([s].[Banner5], 2 + 1, 1) AS tinyint) = CAST(6 AS tinyint)"); } + public override async Task Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(bool async) + { + await base.Include_ThenInclude_which_cycles_back_but_also_includes_additional_navigations(async); + + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE + WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' +END AS [Discriminator], [t0].[Id], [t0].[AmmunitionType], [t0].[IsAutomatic], [t0].[Name], [t0].[OwnerFullName], [t0].[SynergyWithId], [t0].[Nickname], [t0].[SquadId], [t0].[AssignedCityName], [t0].[CityOfBirthName], [t0].[FullName], [t0].[HasSoulPatch], [t0].[LeaderNickname], [t0].[LeaderSquadId], [t0].[Rank], [t0].[Discriminator], [t0].[Name0], [t0].[Location], [t0].[Nation] +FROM [Gears] AS [g] +LEFT JOIN [Officers] AS [o] ON ([g].[Nickname] = [o].[Nickname]) AND ([g].[SquadId] = [o].[SquadId]) +LEFT JOIN ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [t].[Discriminator], [c].[Name] AS [Name0], [c].[Location], [c].[Nation] + FROM [Weapons] AS [w] + LEFT JOIN ( + SELECT [g0].[Nickname], [g0].[SquadId], [g0].[AssignedCityName], [g0].[CityOfBirthName], [g0].[FullName], [g0].[HasSoulPatch], [g0].[LeaderNickname], [g0].[LeaderSquadId], [g0].[Rank], CASE + WHEN [o0].[Nickname] IS NOT NULL THEN N'Officer' + END AS [Discriminator] + FROM [Gears] AS [g0] + LEFT JOIN [Officers] AS [o0] ON ([g0].[Nickname] = [o0].[Nickname]) AND ([g0].[SquadId] = [o0].[SquadId]) + ) AS [t] ON [w].[OwnerFullName] = [t].[FullName] + LEFT JOIN [Cities] AS [c] ON [t].[AssignedCityName] = [c].[Name] +) AS [t0] ON [g].[FullName] = [t0].[OwnerFullName] +ORDER BY [g].[Nickname], [g].[SquadId], [t0].[Id], [t0].[Nickname], [t0].[SquadId], [t0].[Name0]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); }