diff --git a/test/EFCore.Relational.Specification.Tests/Query/OwnedQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/OwnedQueryRelationalTestBase.cs index 56e0edd6692..55c7044d079 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/OwnedQueryRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/OwnedQueryRelationalTestBase.cs @@ -1,9 +1,10 @@ // 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.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; namespace Microsoft.EntityFrameworkCore.Query { @@ -15,6 +16,101 @@ protected OwnedQueryRelationalTestBase(TFixture fixture) { } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Query_for_base_type_loads_all_owned_navs_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().AsSplitQuery()); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Query_for_branch_type_loads_all_owned_navs_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().AsSplitQuery()); + } + + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Query_when_subquery_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Distinct().AsSplitQuery() + .OrderBy(p => p.Id) + .Take(5) + .Select(op => new { op }), + assertOrder: true, + elementAsserter: (e, a) => AssertEqual(e.op, a.op)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Project_multiple_owned_navigations_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().OrderBy(p => p.Id).AsSplitQuery() + .Select( + p => new + { + p.Orders, + p.PersonAddress, + p.PersonAddress.Country.Planet + }), + assertOrder: true, + elementAsserter: (e, a) => + { + AssertCollection(e.Orders, a.Orders); + AssertEqual(e.PersonAddress, a.PersonAddress); + AssertEqual(e.Planet, a.Planet); + }); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().OrderBy(p => p.Id).Select(p => p.PersonAddress.Country.Planet.Moons).AsSplitQuery(), + assertOrder: true, + elementAsserter: (e, a) => AssertCollection(e, a)); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Query_with_OfType_eagerly_loads_correct_owned_navigations_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().OfType().AsSplitQuery()); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Unmapped_property_projection_loads_owned_navigations_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(e => e.Id == 1).AsTracking().Select(e => new { e.ReadOnlyProperty }).AsSplitQuery(), + entryCount: 5); + } + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Can_query_on_indexer_properties_split(bool async) + { + return AssertQuery( + async, + ss => ss.Set().Where(c => (string)c["Name"] == "Mona Cy").AsSplitQuery()); + } + protected virtual bool CanExecuteQueryString => false; protected override QueryAsserter CreateQueryAsserter(TFixture fixture) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs index 1147aaedcac..56fd7fd8065 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/OwnedQuerySqlServerTest.cs @@ -772,6 +772,156 @@ FROM [Order] AS [o0] WHERE ([o].[Id] = [o0].[ClientId]) AND (DATEPART(year, [o0].[OrderDate]) = 2018)) = 1"); } + public override async Task Query_for_base_type_loads_all_owned_navs_split(bool async) + { + await base.Query_for_base_type_loads_all_owned_navs_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[Id], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] AS [o] +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o].[Id] +FROM [OwnedPerson] AS [o] +INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] +ORDER BY [o].[Id]"); + } + + public override async Task Query_for_branch_type_loads_all_owned_navs_split(bool async) + { + await base.Query_for_branch_type_loads_all_owned_navs_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[Id], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] AS [o] +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o].[Id] +FROM [OwnedPerson] AS [o] +INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Discriminator] IN (N'Branch', N'LeafA') +ORDER BY [o].[Id]"); + } + + public override async Task Query_when_subquery_split(bool async) + { + await base.Query_when_subquery_split(async); + + AssertSql( + @"@__p_0='5' + +SELECT [t0].[Id], [t0].[Discriminator], [t0].[Name], [t0].[PersonAddress_AddressLine], [t0].[PersonAddress_PlaceType], [t0].[PersonAddress_ZipCode], [t0].[PersonAddress_Country_Name], [t0].[PersonAddress_Country_PlanetId], [t0].[BranchAddress_BranchName], [t0].[BranchAddress_PlaceType], [t0].[BranchAddress_Country_Name], [t0].[BranchAddress_Country_PlanetId], [t0].[LeafBAddress_LeafBType], [t0].[LeafBAddress_PlaceType], [t0].[Id0], [t0].[LeafBAddress_Country_Name], [t0].[LeafBAddress_Country_PlanetId], [t0].[LeafAAddress_LeafType], [t0].[LeafAAddress_PlaceType], [t0].[LeafAAddress_Country_Name], [t0].[LeafAAddress_Country_PlanetId] +FROM ( + SELECT TOP(@__p_0) [t].[Id], [t].[Discriminator], [t].[Name], [t].[PersonAddress_AddressLine], [t].[PersonAddress_PlaceType], [t].[PersonAddress_ZipCode], [t].[PersonAddress_Country_Name], [t].[PersonAddress_Country_PlanetId], [t].[BranchAddress_BranchName], [t].[BranchAddress_PlaceType], [t].[BranchAddress_Country_Name], [t].[BranchAddress_Country_PlanetId], [t].[LeafBAddress_LeafBType], [t].[LeafBAddress_PlaceType], [t].[Id0], [t].[LeafBAddress_Country_Name], [t].[LeafBAddress_Country_PlanetId], [t].[LeafAAddress_LeafType], [t].[LeafAAddress_PlaceType], [t].[LeafAAddress_Country_Name], [t].[LeafAAddress_Country_PlanetId] + FROM ( + SELECT DISTINCT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[Id] AS [Id0], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] + FROM [OwnedPerson] AS [o] + ) AS [t] + ORDER BY [t].[Id] +) AS [t0] +ORDER BY [t0].[Id]", + // + @"@__p_0='5' + +SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [t0].[Id] +FROM ( + SELECT TOP(@__p_0) [t].[Id], [t].[Discriminator], [t].[Name] + FROM ( + SELECT DISTINCT [o].[Id], [o].[Discriminator], [o].[Name] + FROM [OwnedPerson] AS [o] + ) AS [t] + ORDER BY [t].[Id] +) AS [t0] +INNER JOIN [Order] AS [o0] ON [t0].[Id] = [o0].[ClientId] +ORDER BY [t0].[Id]"); + } + + public override async Task Project_multiple_owned_navigations_split(bool async) + { + await base.Project_multiple_owned_navigations_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [p].[Id], [p].[StarId] +FROM [OwnedPerson] AS [o] +LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +ORDER BY [o].[Id], [p].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o].[Id], [p].[Id] +FROM [OwnedPerson] AS [o] +LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] +ORDER BY [o].[Id], [p].[Id]"); + } + + public override async Task Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_split(bool async) + { + await base.Navigation_rewrite_on_owned_reference_followed_by_regular_entity_and_collection_split(async); + + AssertSql( + @"SELECT [o].[Id], [p].[Id] +FROM [OwnedPerson] AS [o] +LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +ORDER BY [o].[Id], [p].[Id]", + // + @"SELECT [m].[Id], [m].[Diameter], [m].[PlanetId], [o].[Id], [p].[Id] +FROM [OwnedPerson] AS [o] +LEFT JOIN [Planet] AS [p] ON [o].[PersonAddress_Country_PlanetId] = [p].[Id] +INNER JOIN [Moon] AS [m] ON [p].[Id] = [m].[PlanetId] +ORDER BY [o].[Id], [p].[Id]"); + } + + public override async Task Query_with_OfType_eagerly_loads_correct_owned_navigations_split(bool async) + { + await base.Query_with_OfType_eagerly_loads_correct_owned_navigations_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[Id], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] AS [o] +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o].[Id] +FROM [OwnedPerson] AS [o] +INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Discriminator] = N'LeafA' +ORDER BY [o].[Id]"); + } + + public override async Task Unmapped_property_projection_loads_owned_navigations_split(bool async) + { + await base.Unmapped_property_projection_loads_owned_navigations_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[Id], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] AS [o] +WHERE [o].[Id] = 1 +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o].[Id] +FROM [OwnedPerson] AS [o] +INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Id] = 1 +ORDER BY [o].[Id]"); + } + + public override async Task Can_query_on_indexer_properties_split(bool async) + { + await base.Can_query_on_indexer_properties_split(async); + + AssertSql( + @"SELECT [o].[Id], [o].[Discriminator], [o].[Name], [o].[PersonAddress_AddressLine], [o].[PersonAddress_PlaceType], [o].[PersonAddress_ZipCode], [o].[PersonAddress_Country_Name], [o].[PersonAddress_Country_PlanetId], [o].[BranchAddress_BranchName], [o].[BranchAddress_PlaceType], [o].[BranchAddress_Country_Name], [o].[BranchAddress_Country_PlanetId], [o].[LeafBAddress_LeafBType], [o].[LeafBAddress_PlaceType], [o].[Id], [o].[LeafBAddress_Country_Name], [o].[LeafBAddress_Country_PlanetId], [o].[LeafAAddress_LeafType], [o].[LeafAAddress_PlaceType], [o].[LeafAAddress_Country_Name], [o].[LeafAAddress_Country_PlanetId] +FROM [OwnedPerson] AS [o] +WHERE [o].[Name] = N'Mona Cy' +ORDER BY [o].[Id]", + // + @"SELECT [o0].[ClientId], [o0].[Id], [o0].[OrderDate], [o].[Id] +FROM [OwnedPerson] AS [o] +INNER JOIN [Order] AS [o0] ON [o].[Id] = [o0].[ClientId] +WHERE [o].[Name] = N'Mona Cy' +ORDER BY [o].[Id]"); + } + private void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected);