Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/EFCore.Relational/Metadata/Internal/RelationalModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,23 @@ private static void CreateTableMapping(

foreach (var complexProperty in mappedType.GetComplexProperties())
{
// For TPT: skip complex properties declared on base entity types that have their own table.
// Those complex properties will be processed when mapping the declaring entity type's own table.
// For TPC, all properties (including inherited) must be included in each concrete table, so skip this check.
if (mappedType is IEntityType mappedEntityType
&& mappedEntityType.GetMappingStrategy() != RelationalAnnotationNames.TpcMappingStrategy
&& complexProperty.DeclaringType is IEntityType complexPropertyDeclaringEntityType
&& complexPropertyDeclaringEntityType != mappedEntityType)
{
var declaringTableName = complexPropertyDeclaringEntityType.GetTableName();
if (declaringTableName != null
&& (declaringTableName != mappedTable.Name
|| complexPropertyDeclaringEntityType.GetSchema() != mappedTable.Schema))
{
continue;
}
}

var complexType = complexProperty.ComplexType;

var complexTableMappings =
Expand Down
29 changes: 29 additions & 0 deletions test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3322,6 +3322,27 @@ public void Complex_property_json_column_is_nullable_in_TPH_hierarchy()
Assert.IsType<JsonColumn>(jsonColumn);
}

[ConditionalFact]
public void Complex_property_json_column_is_not_duplicated_in_TPT_child_tables()
{
var modelBuilder = CreateConventionModelBuilder();

modelBuilder.Entity<TptBaseEntityWithComplexProperty>()
.UseTptMappingStrategy()
.ComplexProperty(e => e.ComplexProperty, b => b.ToJson());
modelBuilder.Entity<TptDerivedEntityWithoutComplexProperty>();

var model = modelBuilder.FinalizeModel();
var relationalModel = model.GetRelationalModel();

var baseTable = relationalModel.Tables.Single(t => t.Name == nameof(TptBaseEntityWithComplexProperty));
var childTable = relationalModel.Tables.Single(t => t.Name == nameof(TptDerivedEntityWithoutComplexProperty));

// The JSON column for the base complex property must appear only in the base table
Assert.Contains(baseTable.Columns, c => c.Name == nameof(TptBaseEntityWithComplexProperty.ComplexProperty));
Assert.DoesNotContain(childTable.Columns, c => c.Name == nameof(TptBaseEntityWithComplexProperty.ComplexProperty));
}

[ConditionalFact]
public void Can_use_relational_model_with_functions_and_json_owned_types()
{
Expand Down Expand Up @@ -3497,6 +3518,14 @@ private class TphEntityWithComplexProperty : TphBaseEntity
public ComplexData ComplexProperty { get; set; }
}

private abstract class TptBaseEntityWithComplexProperty
{
public int Id { get; set; }
public ComplexData ComplexProperty { get; set; }
}

private class TptDerivedEntityWithoutComplexProperty : TptBaseEntityWithComplexProperty;

[ComplexType]
private class ComplexData
{
Expand Down