From 379145937d8b107b1ea9aeadc006e6335ea22f76 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Fri, 19 Jan 2024 16:33:05 +0000 Subject: [PATCH 1/2] Add complex type mappings to the default relational mappings Replaces #32816 Fixes #32699 As discussed, leaving FromSql to use the default mappings, but add complex types to the default mappings. --- .../Metadata/Internal/RelationalModel.cs | 106 +++++++--- .../Query/SqlExpressions/SelectExpression.cs | 7 +- .../Query/ComplexTypeQuerySqlServerTest.cs | 117 +++++++++++ .../ComplexTypes/DbContextModelBuilder.cs | 181 ++++++++++++++++-- 4 files changed, 362 insertions(+), 49 deletions(-) diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs index 67dc9221560..fba07873565 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Data; +using System.Text; using System.Text.Json; namespace Microsoft.EntityFrameworkCore.Metadata.Internal; @@ -323,32 +323,7 @@ private static void AddDefaultMappings( } else { - foreach (var property in entityType.GetProperties()) - { - var columnName = property.IsPrimaryKey() || isTpc || isTph || property.DeclaringType == mappedType - ? property.GetColumnName() - : null; - if (columnName == null) - { - continue; - } - - var column = (ColumnBase?)defaultTable.FindColumn(columnName); - if (column == null) - { - column = new ColumnBase(columnName, property.GetColumnType(), defaultTable) - { - IsNullable = property.IsColumnNullable() - }; - defaultTable.Columns.Add(columnName, column); - } - else if (!property.IsColumnNullable()) - { - column.IsNullable = false; - } - - CreateColumnMapping(column, property, tableMapping); - } + CreateDefaultColumnMapping(entityType, mappedType, defaultTable, tableMapping, isTph, isTpc); } if (((ITableMappingBase)tableMapping).ColumnMappings.Any() @@ -369,6 +344,83 @@ private static void AddDefaultMappings( tableMappings.Reverse(); } + private static void CreateDefaultColumnMapping( + ITypeBase typeBase, + ITypeBase mappedType, + TableBase defaultTable, + TableMappingBase tableMapping, + bool isTph, + bool isTpc) + { + foreach (var property in typeBase.GetProperties()) + { + var columnName = property.IsPrimaryKey() || isTpc || isTph || property.DeclaringType == mappedType + ? GetColumnName(property) + : null; + + if (columnName == null) + { + continue; + } + + var column = (ColumnBase?)defaultTable.FindColumn(columnName); + if (column == null) + { + column = new ColumnBase(columnName, property.GetColumnType(), defaultTable) + { + IsNullable = property.IsColumnNullable() + }; + defaultTable.Columns.Add(columnName, column); + } + else if (!property.IsColumnNullable()) + { + column.IsNullable = false; + } + + CreateColumnMapping(column, property, tableMapping); + } + + foreach (var complexProperty in typeBase.GetDeclaredComplexProperties()) + { + var complexType = complexProperty.ComplexType; + tableMapping = new TableMappingBase(complexType, defaultTable, includesDerivedTypes: null); + + CreateDefaultColumnMapping(complexType, complexType, defaultTable, tableMapping, isTph, isTpc); + + var tableMappings = (List>?)complexType + .FindRuntimeAnnotationValue(RelationalAnnotationNames.DefaultMappings); + if (tableMappings == null) + { + tableMappings = new List>(); + complexType.AddRuntimeAnnotation(RelationalAnnotationNames.DefaultMappings, tableMappings); + } + tableMappings.Add(tableMapping); + + defaultTable.ComplexTypeMappings.Add(tableMapping); + } + + static string GetColumnName(IProperty property) + { + var complexType = property.DeclaringType as IComplexType; + if (complexType != null) + { + var builder = new StringBuilder(); + builder.Append(property.Name); + while (complexType != null) + { + builder.Insert(0, "_"); + builder.Insert(0, complexType.ComplexProperty.Name); + + complexType = complexType.ComplexProperty.DeclaringType as IComplexType; + } + + return builder.ToString(); + } + + return property.GetColumnName(); + } + } + private static void AddTables( RelationalModel databaseModel, IEntityType entityType, diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 0b2b9b1aac2..874a5d5fa7b 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -2564,8 +2564,11 @@ public static StructuralTypeShaperExpression GenerateComplexPropertyShaperExpres // We do not support complex type splitting, so we will only ever have a single table/view mapping to it. var complexTypeTable = complexProperty.ComplexType.GetViewOrTableMappings().Single().Table; - var tableReferenceExpression = containerProjection.TableMap[complexTypeTable]; - + if (!containerProjection.TableMap.TryGetValue(complexTypeTable, out var tableReferenceExpression)) + { + complexTypeTable = complexProperty.ComplexType.GetDefaultMappings().Single().Table; + tableReferenceExpression = containerProjection.TableMap[complexTypeTable]; + } var isComplexTypeNullable = containerProjection.IsNullable || complexProperty.IsNullable; // If the complex property is declared on a type that's derived relative to the type being projected, the projected column is diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs index 121f5299a24..9060eebbad9 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.EntityFrameworkCore.TestModels.ComplexTypeModel; + namespace Microsoft.EntityFrameworkCore.Query; public class ComplexTypeQuerySqlServerTest : ComplexTypeQueryRelationalTestBase< @@ -742,6 +744,121 @@ public override async Task Union_two_different_struct_complex_type(bool async) AssertSql(); } + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Filter_on_property_inside_complex_type_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + """ +SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_Tags], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] +FROM [Customer] AS [c] +WHERE [c].[ShippingAddress_ZipCode] = 7728 +"""), + ss => ss.Set().Where(c => c.ShippingAddress.ZipCode == 07728)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Filter_on_property_inside_complex_type_after_subquery_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSql( + $""" + SELECT DISTINCT [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_Tags], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_Tags], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName] + FROM ( + SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_Tags], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + ORDER BY [c].[Id] + OFFSET {1} ROWS + ) AS [t] + WHERE [t].[ShippingAddress_ZipCode] = 7728 + """), + ss => ss.Set() + .OrderBy(c => c.Id) + .Skip(1) + .Distinct() + .Where(c => c.ShippingAddress.ZipCode == 07728)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Load_complex_type_after_subquery_on_entity_type_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSql( + $""" + SELECT DISTINCT [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_Tags], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_Tags], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName] + FROM ( + SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_Tags], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + ORDER BY [c].[Id] + OFFSET {1} ROWS + ) AS [t] + """), + ss => ss.Set() + .OrderBy(c => c.Id) + .Skip(1) + .Distinct()); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_complex_type_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + """ + SELECT [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + """).Select(c => c.ShippingAddress), + ss => ss.Set().Select(c => c.ShippingAddress)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_nested_complex_type_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + """ + SELECT [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + """).Select(c => c.ShippingAddress.Country), + ss => ss.Set().Select(c => c.ShippingAddress.Country)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_single_property_on_nested_complex_type_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + """ + SELECT [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + """).Select(c => c.ShippingAddress.Country.FullName), + ss => ss.Set().Select(c => c.ShippingAddress.Country.FullName)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_complex_type_Where_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + """ + SELECT [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + """).Select(c => c.ShippingAddress).Where(a => a.ZipCode == 07728), + ss => ss.Set().Select(c => c.ShippingAddress).Where(a => a.ZipCode == 07728)); + + [ConditionalTheory] + [MemberData(nameof(IsAsyncData))] + public virtual Task Select_complex_type_Distinct_with_FromSql(bool async) + => AssertQuery( + async, + ss => ((DbSet)ss.Set()).FromSqlRaw( + """ + SELECT [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_Tags], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName] + FROM [Customer] AS [c] + """).Select(c => c.ShippingAddress).Distinct(), + ss => ss.Set().Select(c => c.ShippingAddress).Distinct()); + [ConditionalFact] public virtual void Check_all_tests_overridden() => TestHelpers.AssertAllMethodsOverridden(GetType()); diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs index 259fd54d64d..d82d8d6e9db 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs @@ -72,6 +72,111 @@ private IRelationalModel CreateRelationalModel() microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("FlagsEnum2", flagsEnum2ColumnBase); var idColumnBase = new ColumnBase("Id", "bigint", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase); microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Id", idColumnBase); + var owned_DetailsColumnBase = new ColumnBase("Owned_Details", "varchar(64)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Details", owned_DetailsColumnBase); + var owned_NumberColumnBase = new ColumnBase("Owned_Number", "int", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Number", owned_NumberColumnBase); + var owned_Principal_AlternateIdColumnBase = new ColumnBase("Owned_Principal_AlternateId", "uniqueidentifier", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_AlternateId", owned_Principal_AlternateIdColumnBase); + var owned_Principal_Enum1ColumnBase = new ColumnBase("Owned_Principal_Enum1", "int", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_Enum1", owned_Principal_Enum1ColumnBase); + var owned_Principal_Enum2ColumnBase = new ColumnBase("Owned_Principal_Enum2", "int", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_Enum2", owned_Principal_Enum2ColumnBase); + var owned_Principal_FlagsEnum1ColumnBase = new ColumnBase("Owned_Principal_FlagsEnum1", "int", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_FlagsEnum1", owned_Principal_FlagsEnum1ColumnBase); + var owned_Principal_FlagsEnum2ColumnBase = new ColumnBase("Owned_Principal_FlagsEnum2", "int", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_FlagsEnum2", owned_Principal_FlagsEnum2ColumnBase); + var owned_Principal_IdColumnBase = new ColumnBase("Owned_Principal_Id", "bigint", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_Id", owned_Principal_IdColumnBase); + var owned_Principal_RefTypeArrayColumnBase = new ColumnBase("Owned_Principal_RefTypeArray", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_RefTypeArray", owned_Principal_RefTypeArrayColumnBase); + var owned_Principal_RefTypeEnumerableColumnBase = new ColumnBase("Owned_Principal_RefTypeEnumerable", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_RefTypeEnumerable", owned_Principal_RefTypeEnumerableColumnBase); + var owned_Principal_RefTypeIListColumnBase = new ColumnBase("Owned_Principal_RefTypeIList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_RefTypeIList", owned_Principal_RefTypeIListColumnBase); + var owned_Principal_RefTypeListColumnBase = new ColumnBase("Owned_Principal_RefTypeList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_RefTypeList", owned_Principal_RefTypeListColumnBase); + var owned_Principal_ValueTypeArrayColumnBase = new ColumnBase("Owned_Principal_ValueTypeArray", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_ValueTypeArray", owned_Principal_ValueTypeArrayColumnBase); + var owned_Principal_ValueTypeEnumerableColumnBase = new ColumnBase("Owned_Principal_ValueTypeEnumerable", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_ValueTypeEnumerable", owned_Principal_ValueTypeEnumerableColumnBase); + var owned_Principal_ValueTypeIListColumnBase = new ColumnBase("Owned_Principal_ValueTypeIList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_ValueTypeIList", owned_Principal_ValueTypeIListColumnBase); + var owned_Principal_ValueTypeListColumnBase = new ColumnBase("Owned_Principal_ValueTypeList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_Principal_ValueTypeList", owned_Principal_ValueTypeListColumnBase); + var owned_RefTypeArrayColumnBase = new ColumnBase("Owned_RefTypeArray", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_RefTypeArray", owned_RefTypeArrayColumnBase); + var owned_RefTypeEnumerableColumnBase = new ColumnBase("Owned_RefTypeEnumerable", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_RefTypeEnumerable", owned_RefTypeEnumerableColumnBase); + var owned_RefTypeIListColumnBase = new ColumnBase("Owned_RefTypeIList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_RefTypeIList", owned_RefTypeIListColumnBase); + var owned_RefTypeListColumnBase = new ColumnBase("Owned_RefTypeList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_RefTypeList", owned_RefTypeListColumnBase); + var owned_ValueTypeArrayColumnBase = new ColumnBase("Owned_ValueTypeArray", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_ValueTypeArray", owned_ValueTypeArrayColumnBase); + var owned_ValueTypeEnumerableColumnBase = new ColumnBase("Owned_ValueTypeEnumerable", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_ValueTypeEnumerable", owned_ValueTypeEnumerableColumnBase); + var owned_ValueTypeIListColumnBase = new ColumnBase("Owned_ValueTypeIList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_ValueTypeIList", owned_ValueTypeIListColumnBase); + var owned_ValueTypeListColumnBase = new ColumnBase("Owned_ValueTypeList", "nvarchar(max)", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) + { + IsNullable = true + }; + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.Columns.Add("Owned_ValueTypeList", owned_ValueTypeListColumnBase); var principalBaseIdColumnBase = new ColumnBase("PrincipalBaseId", "bigint", microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase) { IsNullable = true @@ -784,6 +889,22 @@ private IRelationalModel CreateRelationalModel() var ownedType = principalBase.FindComplexProperty("Owned")!.ComplexType; + var defaultTableMappings0 = new List>(); + ownedType.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings0); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0 = new TableMappingBase(ownedType, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase, null); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0, false); + defaultTableMappings0.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_DetailsColumnBase, ownedType.FindProperty("Details")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_NumberColumnBase, ownedType.FindProperty("Number")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_RefTypeArrayColumnBase, ownedType.FindProperty("RefTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_RefTypeEnumerableColumnBase, ownedType.FindProperty("RefTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_RefTypeIListColumnBase, ownedType.FindProperty("RefTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_RefTypeListColumnBase, ownedType.FindProperty("RefTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_ValueTypeArrayColumnBase, ownedType.FindProperty("ValueTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_ValueTypeEnumerableColumnBase, ownedType.FindProperty("ValueTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_ValueTypeIListColumnBase, ownedType.FindProperty("ValueTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + RelationalModel.CreateColumnMapping((ColumnBase)owned_ValueTypeListColumnBase, ownedType.FindProperty("ValueTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + var tableMappings0 = new List(); ownedType.SetRuntimeAnnotation("Relational:TableMappings", tableMappings0); var principalBaseTableMapping0 = new TableMapping(ownedType, principalBaseTable, true); @@ -802,6 +923,26 @@ private IRelationalModel CreateRelationalModel() var principalBase0 = ownedType.FindComplexProperty("Principal")!.ComplexType; + var defaultTableMappings1 = new List>(); + principalBase0.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings1); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1 = new TableMappingBase(principalBase0, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase, null); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1, false); + defaultTableMappings1.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_AlternateIdColumnBase, principalBase0.FindProperty("AlternateId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_Enum1ColumnBase, principalBase0.FindProperty("Enum1")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_Enum2ColumnBase, principalBase0.FindProperty("Enum2")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_FlagsEnum1ColumnBase, principalBase0.FindProperty("FlagsEnum1")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_FlagsEnum2ColumnBase, principalBase0.FindProperty("FlagsEnum2")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_IdColumnBase, principalBase0.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_RefTypeArrayColumnBase, principalBase0.FindProperty("RefTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_RefTypeEnumerableColumnBase, principalBase0.FindProperty("RefTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_RefTypeIListColumnBase, principalBase0.FindProperty("RefTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_RefTypeListColumnBase, principalBase0.FindProperty("RefTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_ValueTypeArrayColumnBase, principalBase0.FindProperty("ValueTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_ValueTypeEnumerableColumnBase, principalBase0.FindProperty("ValueTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_ValueTypeIListColumnBase, principalBase0.FindProperty("ValueTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + RelationalModel.CreateColumnMapping((ColumnBase)owned_Principal_ValueTypeListColumnBase, principalBase0.FindProperty("ValueTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase1); + var tableMappings1 = new List(); principalBase0.SetRuntimeAnnotation("Relational:TableMappings", tableMappings1); var principalBaseTableMapping1 = new TableMapping(principalBase0, principalBaseTable, true); @@ -824,26 +965,26 @@ private IRelationalModel CreateRelationalModel() var principalDerived = FindEntityType("Microsoft.EntityFrameworkCore.Scaffolding.CompiledModelTestBase+PrincipalDerived>")!; - var defaultTableMappings0 = new List>(); - principalDerived.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings0); - var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0 = new TableMappingBase(principalDerived, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase, null); - microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0, false); - defaultTableMappings0.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase, principalDerived.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)discriminatorColumnBase, principalDerived.FindProperty("Discriminator")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)enum1ColumnBase, principalDerived.FindProperty("Enum1")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)enum2ColumnBase, principalDerived.FindProperty("Enum2")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)flagsEnum1ColumnBase, principalDerived.FindProperty("FlagsEnum1")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)flagsEnum2ColumnBase, principalDerived.FindProperty("FlagsEnum2")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)principalBaseIdColumnBase, principalDerived.FindProperty("PrincipalBaseId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)refTypeArrayColumnBase, principalDerived.FindProperty("RefTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)refTypeEnumerableColumnBase, principalDerived.FindProperty("RefTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)refTypeIListColumnBase, principalDerived.FindProperty("RefTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)refTypeListColumnBase, principalDerived.FindProperty("RefTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)valueTypeArrayColumnBase, principalDerived.FindProperty("ValueTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)valueTypeEnumerableColumnBase, principalDerived.FindProperty("ValueTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)valueTypeIListColumnBase, principalDerived.FindProperty("ValueTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); - RelationalModel.CreateColumnMapping((ColumnBase)valueTypeListColumnBase, principalDerived.FindProperty("ValueTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase0); + var defaultTableMappings2 = new List>(); + principalDerived.SetRuntimeAnnotation("Relational:DefaultMappings", defaultTableMappings2); + var microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2 = new TableMappingBase(principalDerived, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase, null); + microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseTableBase.AddTypeMapping(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2, false); + defaultTableMappings2.Add(microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)idColumnBase, principalDerived.FindProperty("Id")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)discriminatorColumnBase, principalDerived.FindProperty("Discriminator")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)enum1ColumnBase, principalDerived.FindProperty("Enum1")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)enum2ColumnBase, principalDerived.FindProperty("Enum2")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)flagsEnum1ColumnBase, principalDerived.FindProperty("FlagsEnum1")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)flagsEnum2ColumnBase, principalDerived.FindProperty("FlagsEnum2")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)principalBaseIdColumnBase, principalDerived.FindProperty("PrincipalBaseId")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)refTypeArrayColumnBase, principalDerived.FindProperty("RefTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)refTypeEnumerableColumnBase, principalDerived.FindProperty("RefTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)refTypeIListColumnBase, principalDerived.FindProperty("RefTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)refTypeListColumnBase, principalDerived.FindProperty("RefTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)valueTypeArrayColumnBase, principalDerived.FindProperty("ValueTypeArray")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)valueTypeEnumerableColumnBase, principalDerived.FindProperty("ValueTypeEnumerable")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)valueTypeIListColumnBase, principalDerived.FindProperty("ValueTypeIList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); + RelationalModel.CreateColumnMapping((ColumnBase)valueTypeListColumnBase, principalDerived.FindProperty("ValueTypeList")!, microsoftEntityFrameworkCoreScaffoldingCompiledModelTestBasePrincipalBaseMappingBase2); var tableMappings2 = new List(); principalDerived.SetRuntimeAnnotation("Relational:TableMappings", tableMappings2); From 3fdb4d0bcbea517f676bbe9d036e80a62519d861 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Tue, 23 Jan 2024 10:42:19 +0000 Subject: [PATCH 2/2] Add note to SelectExpression --- src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 874a5d5fa7b..b7dc3f19791 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -2563,6 +2563,7 @@ public static StructuralTypeShaperExpression GenerateComplexPropertyShaperExpres var propertyExpressionMap = new Dictionary(); // 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 = complexProperty.ComplexType.GetViewOrTableMappings().Single().Table; if (!containerProjection.TableMap.TryGetValue(complexTypeTable, out var tableReferenceExpression)) {