Skip to content

Commit 6a7fa61

Browse files
Fix complex property JSON column not marked nullable in TPH hierarchy (#37781)
Fixes #37404 Co-authored-by: AndriySvyryd <[email protected]>
1 parent a24cf33 commit 6a7fa61

3 files changed

Lines changed: 42 additions & 2 deletions

File tree

src/EFCore.Relational/Metadata/Internal/RelationalModel.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,8 +634,13 @@ private static void CreateContainerColumn<TColumnMappingBase>(
634634
{
635635
complexType = (IComplexType)mappedType;
636636
#pragma warning disable EF1001 // Internal EF Core API usage.
637+
var chain = complexType.ComplexProperty.GetChainToComplexProperty(fromEntity: true);
637638
jsonColumn.IsNullable = complexType.ComplexProperty.IsNullable
638-
|| complexType.ComplexProperty.GetChainToComplexProperty(fromEntity: true).Any(p => p.IsNullable);
639+
|| (chain[0].DeclaringType is IEntityType declaringEntityType
640+
&& declaringEntityType.BaseType != null
641+
&& (declaringEntityType.GetMappingStrategy() ?? RelationalAnnotationNames.TphMappingStrategy)
642+
== RelationalAnnotationNames.TphMappingStrategy)
643+
|| chain.Any(p => p.IsNullable);
639644
#pragma warning restore EF1001 // Internal EF Core API usage.
640645
}
641646
}

test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3201,6 +3201,26 @@ public void Container_column_type_is_used_for_complex_collection_json_column()
32013201
Assert.IsType<JsonColumn>(jsonColumn);
32023202
}
32033203

3204+
[ConditionalFact]
3205+
public void Complex_property_json_column_is_nullable_in_TPH_hierarchy()
3206+
{
3207+
var modelBuilder = CreateConventionModelBuilder();
3208+
3209+
modelBuilder.Entity<TphBaseEntity>();
3210+
modelBuilder.Entity<EntityWithoutComplexProperty>();
3211+
modelBuilder.Entity<TphEntityWithComplexProperty>()
3212+
.ComplexProperty(e => e.ComplexProperty, b => b.ToJson());
3213+
3214+
var model = modelBuilder.FinalizeModel();
3215+
var relationalModel = model.GetRelationalModel();
3216+
3217+
var table = relationalModel.Tables.Single();
3218+
var jsonColumn = table.Columns.Single(c => c.Name == "ComplexProperty");
3219+
3220+
Assert.True(jsonColumn.IsNullable);
3221+
Assert.IsType<JsonColumn>(jsonColumn);
3222+
}
3223+
32043224
private static IRelationalModel Finalize(TestHelpers.TestModelBuilder modelBuilder)
32053225
=> modelBuilder.FinalizeModel(designTime: true).GetRelationalModel();
32063226

@@ -3318,6 +3338,18 @@ private class EntityWithComplexCollection
33183338
public List<ComplexData> ComplexCollection { get; set; }
33193339
}
33203340

3341+
private abstract class TphBaseEntity
3342+
{
3343+
public int Id { get; set; }
3344+
}
3345+
3346+
private class EntityWithoutComplexProperty : TphBaseEntity;
3347+
3348+
private class TphEntityWithComplexProperty : TphBaseEntity
3349+
{
3350+
public ComplexData ComplexProperty { get; set; }
3351+
}
3352+
33213353
private class ComplexData
33223354
{
33233355
public string Value { get; set; }

test/EFCore.SqlServer.FunctionalTests/Scaffolding/Baselines/ComplexTypes/DbContextModelBuilder.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,10 @@ private IRelationalModel CreateRelationalModel()
406406
var flagsEnum2Column = new Column("FlagsEnum2", "int", principalBaseTable);
407407
principalBaseTable.Columns.Add("FlagsEnum2", flagsEnum2Column);
408408
flagsEnum2Column.Accessors = ColumnAccessorsFactory.CreateGeneric<int>(flagsEnum2Column);
409-
var manyOwnedColumn = new JsonColumn("ManyOwned", "nvarchar(max)", principalBaseTable);
409+
var manyOwnedColumn = new JsonColumn("ManyOwned", "nvarchar(max)", principalBaseTable)
410+
{
411+
IsNullable = true
412+
};
410413
principalBaseTable.Columns.Add("ManyOwned", manyOwnedColumn);
411414
manyOwnedColumn.Accessors = ColumnAccessorsFactory.CreateGeneric<JsonTypePlaceholder>(manyOwnedColumn);
412415
var owned_NumberColumn = new Column("Owned_Number", "int", principalBaseTable);

0 commit comments

Comments
 (0)