From 8c820a167656b555df438baad26dab8aea635ab7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Mon, 24 Nov 2025 23:28:33 +0100 Subject: [PATCH] Work around the lack of complex types in default relational mappings Closes #34627 --- .../Query/SqlExpressions/SelectExpression.cs | 9 ++++-- ...plexJsonMiscellaneousRelationalTestBase.cs | 4 +++ ...plittingMiscellaneousRelationalTestBase.cs | 4 +++ ...igationsMiscellaneousRelationalTestBase.cs | 4 +++ ...wnedJsonMiscellaneousRelationalTestBase.cs | 4 +++ ...igationsMiscellaneousRelationalTestBase.cs | 4 +++ ...plittingMiscellaneousRelationalTestBase.cs | 4 +++ .../RelationalAssociationsTests.cs | 20 +++++++++++++ .../ComplexJsonMiscellaneousSqlServerTest.cs | 13 +++++++++ ...ableSplittingMiscellaneousSqlServerTest.cs | 10 +++++++ .../NavigationsMiscellaneousSqlServerTest.cs | 29 +++++++++++++++++++ .../OwnedJsonMiscellaneousSqlServerTest.cs | 13 +++++++++ ...edNavigationsMiscellaneousSqlServerTest.cs | 29 +++++++++++++++++++ ...ableSplittingMiscellaneousSqlServerTest.cs | 25 ++++++++++++++++ 14 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 test/EFCore.Relational.Specification.Tests/Query/Associations/RelationalAssociationsTests.cs diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 2d57cfb6298..9330291b051 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -2862,7 +2862,8 @@ public static Expression GenerateComplexPropertyShaperExpression( // We do not support complex type splitting, so we will only ever have a single table/view mapping to it. // See Issue #32853 and Issue #31248 - var complexTypeTable = complexType.GetViewOrTableMappings().Single().Table; + var viewOrTableTable = complexType.GetViewOrTableMappings().Single().Table; + var complexTypeTable = viewOrTableTable; if (!containerProjection.TableMap.TryGetValue(complexTypeTable, out var tableAlias)) { @@ -2886,7 +2887,11 @@ public static Expression GenerateComplexPropertyShaperExpression( { var containerColumnName = complexType.GetContainerColumnName(); Check.DebugAssert(containerColumnName is not null, "Complex JSON type without a container column"); - var containerColumn = complexTypeTable.FindColumn(containerColumnName); + + // TODO: when the JSON column is on a FromSql() source, we use the default mappings from the relational model (see just above), + // but those don't yet contain complex types (#34627). We work around this here, get the column from the table mapping instead + // of from the default mapping. + var containerColumn = complexTypeTable.FindColumn(containerColumnName) ?? viewOrTableTable.FindColumn(containerColumnName); Check.DebugAssert(containerColumn is not null, "Complex JSON container table not found on relational table"); // If the source type is a JSON complex type; since we're binding over StructuralTypeProjectionExpression - which represents a relational diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousRelationalTestBase.cs index eefbf36c7e0..2e25c5e6038 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousRelationalTestBase.cs @@ -15,6 +15,10 @@ public ComplexJsonMiscellaneousRelationalTestBase(TFixture fixture, ITestOutputH Fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalFact] + public virtual Task FromSql_on_root() + => RelationalAssociationsTests.FromSql_on_root(this, Fixture); + protected void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs index 385eb0e79e0..a2f83e6fb35 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousRelationalTestBase.cs @@ -15,6 +15,10 @@ public ComplexTableSplittingMiscellaneousRelationalTestBase(TFixture fixture, IT fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalFact] + public virtual Task FromSql_on_root() + => RelationalAssociationsTests.FromSql_on_root(this, Fixture); + protected void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/Navigations/NavigationsMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/Navigations/NavigationsMiscellaneousRelationalTestBase.cs index 8e7fef3b2c0..2dec3c06b05 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/Associations/Navigations/NavigationsMiscellaneousRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/Navigations/NavigationsMiscellaneousRelationalTestBase.cs @@ -13,6 +13,10 @@ public NavigationsMiscellaneousRelationalTestBase(TFixture fixture, ITestOutputH fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalFact] + public virtual Task FromSql_on_root() + => RelationalAssociationsTests.FromSql_on_root(this, Fixture); + protected void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousRelationalTestBase.cs index b63bacab57c..dde74366dca 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousRelationalTestBase.cs @@ -15,6 +15,10 @@ public OwnedJsonMiscellaneousRelationalTestBase(TFixture fixture, ITestOutputHel fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalFact] + public virtual Task FromSql_on_root() + => RelationalAssociationsTests.FromSql_on_root(this, Fixture); + protected void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousRelationalTestBase.cs index 0d0961269f6..b197306b9f0 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousRelationalTestBase.cs @@ -13,6 +13,10 @@ public OwnedNavigationsMiscellaneousRelationalTestBase(TFixture fixture, ITestOu fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalFact] + public virtual Task FromSql_on_root() + => RelationalAssociationsTests.FromSql_on_root(this, Fixture); + public void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousRelationalTestBase.cs index c6ef7514ca8..0acbec652b0 100644 --- a/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousRelationalTestBase.cs +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousRelationalTestBase.cs @@ -15,6 +15,10 @@ public OwnedTableSplittingMiscellaneousRelationalTestBase(TFixture fixture, ITes fixture.TestSqlLoggerFactory.SetTestOutputHelper(testOutputHelper); } + [ConditionalFact] + public virtual Task FromSql_on_root() + => RelationalAssociationsTests.FromSql_on_root(this, Fixture); + protected void AssertSql(params string[] expected) => Fixture.TestSqlLoggerFactory.AssertBaseline(expected); } diff --git a/test/EFCore.Relational.Specification.Tests/Query/Associations/RelationalAssociationsTests.cs b/test/EFCore.Relational.Specification.Tests/Query/Associations/RelationalAssociationsTests.cs new file mode 100644 index 00000000000..035d091317e --- /dev/null +++ b/test/EFCore.Relational.Specification.Tests/Query/Associations/RelationalAssociationsTests.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.EntityFrameworkCore.Query.Associations; + +public class RelationalAssociationsTests +{ + internal static async Task FromSql_on_root(QueryTestBase queryTestBase, TFixture fixture) + where TFixture : SharedStoreFixtureBase, IQueryFixtureBase, new() + { + using var context = fixture.CreateContext(); + var tableName = context.Model.FindEntityType(typeof(RootEntity))?.GetTableName() + ?? throw new UnreachableException("Couldn't find relational table name for RootEntity"); + var sqlGenerationHelper = context.GetService(); + + await queryTestBase.AssertQuery( + ss => ((DbSet)ss.Set()).FromSqlRaw($"SELECT * FROM {sqlGenerationHelper.DelimitIdentifier(tableName)}"), + ss => ss.Set()); + } +} diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousSqlServerTest.cs index e9c8ee7b3a8..341407cb441 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexJson/ComplexJsonMiscellaneousSqlServerTest.cs @@ -146,6 +146,19 @@ WHERE [v].[OptionalAssociate] IS NOT NULL #endregion Value types + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT [m].[Id], [m].[Name], [m].[AssociateCollection], [m].[OptionalAssociate], [m].[RequiredAssociate] +FROM ( + SELECT * FROM [RootEntity] +) AS [m] +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs index 1646768532b..868095884ca 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/ComplexTableSplitting/ComplexTableSplittingMiscellaneousSqlServerTest.cs @@ -84,6 +84,16 @@ WHERE [v].[OptionalAssociate_Id] IS NOT NULL #endregion Value types + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT * FROM [RootEntity] +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousSqlServerTest.cs index 227db34b7c5..1b50f02e3e9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/Navigations/NavigationsMiscellaneousSqlServerTest.cs @@ -96,6 +96,35 @@ FROM [AssociateType] AS [a1] #endregion Simple filters + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT [m].[Id], [m].[Name], [m].[OptionalAssociateId], [m].[RequiredAssociateId], [a].[Id], [n].[Id], [n0].[Id], [a0].[Id], [n1].[Id], [n2].[Id], [s].[Id], [s].[CollectionRootId], [s].[Int], [s].[Ints], [s].[Name], [s].[OptionalNestedAssociateId], [s].[RequiredNestedAssociateId], [s].[String], [s].[Id0], [s].[Id1], [s].[Id2], [s].[CollectionAssociateId], [s].[Int0], [s].[Ints0], [s].[Name0], [s].[String0], [s].[CollectionAssociateId0], [s].[Int1], [s].[Ints1], [s].[Name1], [s].[String1], [s].[CollectionAssociateId1], [s].[Int2], [s].[Ints2], [s].[Name2], [s].[String2], [a].[CollectionRootId], [a].[Int], [a].[Ints], [a].[Name], [a].[OptionalNestedAssociateId], [a].[RequiredNestedAssociateId], [a].[String], [n6].[Id], [n6].[CollectionAssociateId], [n6].[Int], [n6].[Ints], [n6].[Name], [n6].[String], [n].[CollectionAssociateId], [n].[Int], [n].[Ints], [n].[Name], [n].[String], [n0].[CollectionAssociateId], [n0].[Int], [n0].[Ints], [n0].[Name], [n0].[String], [a0].[CollectionRootId], [a0].[Int], [a0].[Ints], [a0].[Name], [a0].[OptionalNestedAssociateId], [a0].[RequiredNestedAssociateId], [a0].[String], [n7].[Id], [n7].[CollectionAssociateId], [n7].[Int], [n7].[Ints], [n7].[Name], [n7].[String], [n1].[CollectionAssociateId], [n1].[Int], [n1].[Ints], [n1].[Name], [n1].[String], [n2].[CollectionAssociateId], [n2].[Int], [n2].[Ints], [n2].[Name], [n2].[String] +FROM ( + SELECT * FROM [RootEntity] +) AS [m] +LEFT JOIN [AssociateType] AS [a] ON [m].[OptionalAssociateId] = [a].[Id] +LEFT JOIN [NestedAssociateType] AS [n] ON [a].[OptionalNestedAssociateId] = [n].[Id] +LEFT JOIN [NestedAssociateType] AS [n0] ON [a].[RequiredNestedAssociateId] = [n0].[Id] +INNER JOIN [AssociateType] AS [a0] ON [m].[RequiredAssociateId] = [a0].[Id] +LEFT JOIN [NestedAssociateType] AS [n1] ON [a0].[OptionalNestedAssociateId] = [n1].[Id] +INNER JOIN [NestedAssociateType] AS [n2] ON [a0].[RequiredNestedAssociateId] = [n2].[Id] +LEFT JOIN ( + SELECT [a1].[Id], [a1].[CollectionRootId], [a1].[Int], [a1].[Ints], [a1].[Name], [a1].[OptionalNestedAssociateId], [a1].[RequiredNestedAssociateId], [a1].[String], [n3].[Id] AS [Id0], [n4].[Id] AS [Id1], [n5].[Id] AS [Id2], [n5].[CollectionAssociateId], [n5].[Int] AS [Int0], [n5].[Ints] AS [Ints0], [n5].[Name] AS [Name0], [n5].[String] AS [String0], [n3].[CollectionAssociateId] AS [CollectionAssociateId0], [n3].[Int] AS [Int1], [n3].[Ints] AS [Ints1], [n3].[Name] AS [Name1], [n3].[String] AS [String1], [n4].[CollectionAssociateId] AS [CollectionAssociateId1], [n4].[Int] AS [Int2], [n4].[Ints] AS [Ints2], [n4].[Name] AS [Name2], [n4].[String] AS [String2] + FROM [AssociateType] AS [a1] + LEFT JOIN [NestedAssociateType] AS [n3] ON [a1].[OptionalNestedAssociateId] = [n3].[Id] + INNER JOIN [NestedAssociateType] AS [n4] ON [a1].[RequiredNestedAssociateId] = [n4].[Id] + LEFT JOIN [NestedAssociateType] AS [n5] ON [a1].[Id] = [n5].[CollectionAssociateId] +) AS [s] ON [m].[Id] = [s].[CollectionRootId] +LEFT JOIN [NestedAssociateType] AS [n6] ON [a].[Id] = [n6].[CollectionAssociateId] +LEFT JOIN [NestedAssociateType] AS [n7] ON [a0].[Id] = [n7].[CollectionAssociateId] +ORDER BY [m].[Id], [a].[Id], [n].[Id], [n0].[Id], [a0].[Id], [n1].[Id], [n2].[Id], [s].[Id], [s].[Id0], [s].[Id1], [s].[Id2], [n6].[Id] +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousSqlServerTest.cs index eddfb5ca660..ec204531776 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedJson/OwnedJsonMiscellaneousSqlServerTest.cs @@ -84,6 +84,19 @@ WHERE CAST(JSON_VALUE([r].[RequiredAssociate], '$.RequiredNestedAssociate.Int') #endregion Simple filters + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT [m].[Id], [m].[Name], [m].[AssociateCollection], [m].[OptionalAssociate], [m].[RequiredAssociate] +FROM ( + SELECT * FROM [RootEntity] +) AS [m] +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousSqlServerTest.cs index 98280a9be26..e86339afe3a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedNavigations/OwnedNavigationsMiscellaneousSqlServerTest.cs @@ -96,6 +96,35 @@ FROM [RelatedCollection] AS [r3] #endregion Simple filters + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT [m].[Id], [m].[Name], [o].[RootEntityId], [o0].[AssociateTypeRootEntityId], [o1].[AssociateTypeRootEntityId], [r].[RootEntityId], [r0].[AssociateTypeRootEntityId], [r1].[AssociateTypeRootEntityId], [s].[RootEntityId], [s].[Id], [s].[Int], [s].[Ints], [s].[Name], [s].[String], [s].[AssociateTypeRootEntityId], [s].[AssociateTypeId], [s].[AssociateTypeRootEntityId0], [s].[AssociateTypeId0], [s].[AssociateTypeRootEntityId1], [s].[AssociateTypeId1], [s].[Id0], [s].[Int0], [s].[Ints0], [s].[Name0], [s].[String0], [s].[Id1], [s].[Int1], [s].[Ints1], [s].[Name1], [s].[String1], [s].[Id2], [s].[Int2], [s].[Ints2], [s].[Name2], [s].[String2], [o].[Id], [o].[Int], [o].[Ints], [o].[Name], [o].[String], [o2].[AssociateTypeRootEntityId], [o2].[Id], [o2].[Int], [o2].[Ints], [o2].[Name], [o2].[String], [o0].[Id], [o0].[Int], [o0].[Ints], [o0].[Name], [o0].[String], [o1].[Id], [o1].[Int], [o1].[Ints], [o1].[Name], [o1].[String], [r].[Id], [r].[Int], [r].[Ints], [r].[Name], [r].[String], [r6].[AssociateTypeRootEntityId], [r6].[Id], [r6].[Int], [r6].[Ints], [r6].[Name], [r6].[String], [r0].[Id], [r0].[Int], [r0].[Ints], [r0].[Name], [r0].[String], [r1].[Id], [r1].[Int], [r1].[Ints], [r1].[Name], [r1].[String] +FROM ( + SELECT * FROM [RootEntity] +) AS [m] +LEFT JOIN [OptionalRelated] AS [o] ON [m].[Id] = [o].[RootEntityId] +LEFT JOIN [OptionalRelated_OptionalNested] AS [o0] ON [o].[RootEntityId] = [o0].[AssociateTypeRootEntityId] +LEFT JOIN [OptionalRelated_RequiredNested] AS [o1] ON [o].[RootEntityId] = [o1].[AssociateTypeRootEntityId] +LEFT JOIN [RequiredRelated] AS [r] ON [m].[Id] = [r].[RootEntityId] +LEFT JOIN [RequiredRelated_OptionalNested] AS [r0] ON [r].[RootEntityId] = [r0].[AssociateTypeRootEntityId] +LEFT JOIN [RequiredRelated_RequiredNested] AS [r1] ON [r].[RootEntityId] = [r1].[AssociateTypeRootEntityId] +LEFT JOIN ( + SELECT [r2].[RootEntityId], [r2].[Id], [r2].[Int], [r2].[Ints], [r2].[Name], [r2].[String], [r3].[AssociateTypeRootEntityId], [r3].[AssociateTypeId], [r4].[AssociateTypeRootEntityId] AS [AssociateTypeRootEntityId0], [r4].[AssociateTypeId] AS [AssociateTypeId0], [r5].[AssociateTypeRootEntityId] AS [AssociateTypeRootEntityId1], [r5].[AssociateTypeId] AS [AssociateTypeId1], [r5].[Id] AS [Id0], [r5].[Int] AS [Int0], [r5].[Ints] AS [Ints0], [r5].[Name] AS [Name0], [r5].[String] AS [String0], [r3].[Id] AS [Id1], [r3].[Int] AS [Int1], [r3].[Ints] AS [Ints1], [r3].[Name] AS [Name1], [r3].[String] AS [String1], [r4].[Id] AS [Id2], [r4].[Int] AS [Int2], [r4].[Ints] AS [Ints2], [r4].[Name] AS [Name2], [r4].[String] AS [String2] + FROM [RelatedCollection] AS [r2] + LEFT JOIN [RelatedCollection_OptionalNested] AS [r3] ON [r2].[RootEntityId] = [r3].[AssociateTypeRootEntityId] AND [r2].[Id] = [r3].[AssociateTypeId] + LEFT JOIN [RelatedCollection_RequiredNested] AS [r4] ON [r2].[RootEntityId] = [r4].[AssociateTypeRootEntityId] AND [r2].[Id] = [r4].[AssociateTypeId] + LEFT JOIN [RelatedCollection_NestedCollection] AS [r5] ON [r2].[RootEntityId] = [r5].[AssociateTypeRootEntityId] AND [r2].[Id] = [r5].[AssociateTypeId] +) AS [s] ON [m].[Id] = [s].[RootEntityId] +LEFT JOIN [OptionalRelated_NestedCollection] AS [o2] ON [o].[RootEntityId] = [o2].[AssociateTypeRootEntityId] +LEFT JOIN [RequiredRelated_NestedCollection] AS [r6] ON [r].[RootEntityId] = [r6].[AssociateTypeRootEntityId] +ORDER BY [m].[Id], [o].[RootEntityId], [o0].[AssociateTypeRootEntityId], [o1].[AssociateTypeRootEntityId], [r].[RootEntityId], [r0].[AssociateTypeRootEntityId], [r1].[AssociateTypeRootEntityId], [s].[RootEntityId], [s].[Id], [s].[AssociateTypeRootEntityId], [s].[AssociateTypeId], [s].[AssociateTypeRootEntityId0], [s].[AssociateTypeId0], [s].[AssociateTypeRootEntityId1], [s].[AssociateTypeId1], [s].[Id0], [o2].[AssociateTypeRootEntityId], [o2].[Id], [r6].[AssociateTypeRootEntityId] +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousSqlServerTest.cs index ae95ec70fc9..fcf81893bea 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/Associations/OwnedTableSplitting/OwnedTableSplittingMiscellaneousSqlServerTest.cs @@ -78,6 +78,31 @@ WHEN [r].[OptionalAssociate_Id] IS NOT NULL AND [r].[OptionalAssociate_Int] IS N #endregion Simple filters + public override async Task FromSql_on_root() + { + await base.FromSql_on_root(); + + AssertSql( + """ +SELECT [m].[Id], [m].[Name], [r].[Id], [r0].[Id], [s].[RootEntityId], [s].[Id], [s].[Int], [s].[Ints], [s].[Name], [s].[String], [s].[AssociateTypeRootEntityId], [s].[AssociateTypeId], [s].[Id0], [s].[Int0], [s].[Ints0], [s].[Name0], [s].[String0], [s].[OptionalNestedAssociate_Id], [s].[OptionalNestedAssociate_Int], [s].[OptionalNestedAssociate_Ints], [s].[OptionalNestedAssociate_Name], [s].[OptionalNestedAssociate_String], [s].[RequiredNestedAssociate_Id], [s].[RequiredNestedAssociate_Int], [s].[RequiredNestedAssociate_Ints], [s].[RequiredNestedAssociate_Name], [s].[RequiredNestedAssociate_String], [r].[OptionalAssociate_Id], [r].[OptionalAssociate_Int], [r].[OptionalAssociate_Ints], [r].[OptionalAssociate_Name], [r].[OptionalAssociate_String], [o].[AssociateTypeRootEntityId], [o].[Id], [o].[Int], [o].[Ints], [o].[Name], [o].[String], [r].[OptionalAssociate_OptionalNestedAssociate_Id], [r].[OptionalAssociate_OptionalNestedAssociate_Int], [r].[OptionalAssociate_OptionalNestedAssociate_Ints], [r].[OptionalAssociate_OptionalNestedAssociate_Name], [r].[OptionalAssociate_OptionalNestedAssociate_String], [r].[OptionalAssociate_RequiredNestedAssociate_Id], [r].[OptionalAssociate_RequiredNestedAssociate_Int], [r].[OptionalAssociate_RequiredNestedAssociate_Ints], [r].[OptionalAssociate_RequiredNestedAssociate_Name], [r].[OptionalAssociate_RequiredNestedAssociate_String], [r0].[RequiredAssociate_Id], [r0].[RequiredAssociate_Int], [r0].[RequiredAssociate_Ints], [r0].[RequiredAssociate_Name], [r0].[RequiredAssociate_String], [r3].[AssociateTypeRootEntityId], [r3].[Id], [r3].[Int], [r3].[Ints], [r3].[Name], [r3].[String], [r0].[RequiredAssociate_OptionalNestedAssociate_Id], [r0].[RequiredAssociate_OptionalNestedAssociate_Int], [r0].[RequiredAssociate_OptionalNestedAssociate_Ints], [r0].[RequiredAssociate_OptionalNestedAssociate_Name], [r0].[RequiredAssociate_OptionalNestedAssociate_String], [r0].[RequiredAssociate_RequiredNestedAssociate_Id], [r0].[RequiredAssociate_RequiredNestedAssociate_Int], [r0].[RequiredAssociate_RequiredNestedAssociate_Ints], [r0].[RequiredAssociate_RequiredNestedAssociate_Name], [r0].[RequiredAssociate_RequiredNestedAssociate_String] +FROM ( + SELECT * FROM [RootEntity] +) AS [m] +LEFT JOIN [RootEntity] AS [r] ON [m].[Id] = [r].[Id] +LEFT JOIN [RootEntity] AS [r0] ON [m].[Id] = [r0].[Id] +LEFT JOIN ( + SELECT [r1].[RootEntityId], [r1].[Id], [r1].[Int], [r1].[Ints], [r1].[Name], [r1].[String], [r2].[AssociateTypeRootEntityId], [r2].[AssociateTypeId], [r2].[Id] AS [Id0], [r2].[Int] AS [Int0], [r2].[Ints] AS [Ints0], [r2].[Name] AS [Name0], [r2].[String] AS [String0], [r1].[OptionalNestedAssociate_Id], [r1].[OptionalNestedAssociate_Int], [r1].[OptionalNestedAssociate_Ints], [r1].[OptionalNestedAssociate_Name], [r1].[OptionalNestedAssociate_String], [r1].[RequiredNestedAssociate_Id], [r1].[RequiredNestedAssociate_Int], [r1].[RequiredNestedAssociate_Ints], [r1].[RequiredNestedAssociate_Name], [r1].[RequiredNestedAssociate_String] + FROM [RelatedCollection] AS [r1] + LEFT JOIN [RelatedCollection_NestedCollection] AS [r2] ON [r1].[RootEntityId] = [r2].[AssociateTypeRootEntityId] AND [r1].[Id] = [r2].[AssociateTypeId] +) AS [s] ON [m].[Id] = [s].[RootEntityId] +LEFT JOIN [OptionalRelated_NestedCollection] AS [o] ON CASE + WHEN [r].[OptionalAssociate_Id] IS NOT NULL AND [r].[OptionalAssociate_Int] IS NOT NULL AND [r].[OptionalAssociate_Ints] IS NOT NULL AND [r].[OptionalAssociate_Name] IS NOT NULL AND [r].[OptionalAssociate_String] IS NOT NULL THEN [r].[Id] +END = [o].[AssociateTypeRootEntityId] +LEFT JOIN [RequiredRelated_NestedCollection] AS [r3] ON [r0].[Id] = [r3].[AssociateTypeRootEntityId] +ORDER BY [m].[Id], [r].[Id], [r0].[Id], [s].[RootEntityId], [s].[Id], [s].[AssociateTypeRootEntityId], [s].[AssociateTypeId], [s].[Id0], [o].[AssociateTypeRootEntityId], [o].[Id], [r3].[AssociateTypeRootEntityId] +"""); + } + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType());