diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs index 9f6c26fb8fb..1df7270a58f 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalModel.cs @@ -634,8 +634,13 @@ private static void CreateContainerColumn( { complexType = (IComplexType)mappedType; #pragma warning disable EF1001 // Internal EF Core API usage. + var chain = complexType.ComplexProperty.GetChainToComplexProperty(fromEntity: true); jsonColumn.IsNullable = complexType.ComplexProperty.IsNullable - || complexType.ComplexProperty.GetChainToComplexProperty(fromEntity: true).Any(p => p.IsNullable); + || (chain[0].DeclaringType is IEntityType declaringEntityType + && declaringEntityType.BaseType != null + && (declaringEntityType.GetMappingStrategy() ?? RelationalAnnotationNames.TphMappingStrategy) + == RelationalAnnotationNames.TphMappingStrategy) + || chain.Any(p => p.IsNullable); #pragma warning restore EF1001 // Internal EF Core API usage. } } diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs index cff152fe567..ef756bd56ed 100644 --- a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs +++ b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs @@ -3201,6 +3201,26 @@ public void Container_column_type_is_used_for_complex_collection_json_column() Assert.IsType(jsonColumn); } + [ConditionalFact] + public void Complex_property_json_column_is_nullable_in_TPH_hierarchy() + { + var modelBuilder = CreateConventionModelBuilder(); + + modelBuilder.Entity(); + modelBuilder.Entity(); + modelBuilder.Entity() + .ComplexProperty(e => e.ComplexProperty, b => b.ToJson()); + + var model = modelBuilder.FinalizeModel(); + var relationalModel = model.GetRelationalModel(); + + var table = relationalModel.Tables.Single(); + var jsonColumn = table.Columns.Single(c => c.Name == "ComplexProperty"); + + Assert.True(jsonColumn.IsNullable); + Assert.IsType(jsonColumn); + } + private static IRelationalModel Finalize(TestHelpers.TestModelBuilder modelBuilder) => modelBuilder.FinalizeModel(designTime: true).GetRelationalModel(); @@ -3318,6 +3338,18 @@ private class EntityWithComplexCollection public List ComplexCollection { get; set; } } + private abstract class TphBaseEntity + { + public int Id { get; set; } + } + + private class EntityWithoutComplexProperty : TphBaseEntity; + + private class TphEntityWithComplexProperty : TphBaseEntity + { + public ComplexData ComplexProperty { get; set; } + } + private class ComplexData { public string Value { get; set; } diff --git a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs index e7e1b974016..4b02f75417a 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs @@ -406,7 +406,10 @@ private IRelationalModel CreateRelationalModel() var flagsEnum2Column = new Column("FlagsEnum2", "int", principalBaseTable); principalBaseTable.Columns.Add("FlagsEnum2", flagsEnum2Column); flagsEnum2Column.Accessors = ColumnAccessorsFactory.CreateGeneric(flagsEnum2Column); - var manyOwnedColumn = new JsonColumn("ManyOwned", "nvarchar(max)", principalBaseTable); + var manyOwnedColumn = new JsonColumn("ManyOwned", "nvarchar(max)", principalBaseTable) + { + IsNullable = true + }; principalBaseTable.Columns.Add("ManyOwned", manyOwnedColumn); manyOwnedColumn.Accessors = ColumnAccessorsFactory.CreateGeneric(manyOwnedColumn); var owned_NumberColumn = new Column("Owned_Number", "int", principalBaseTable);