diff --git a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
index 927366e1203..07c895f736e 100644
--- a/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
+++ b/src/EFCore.Design/Migrations/Design/CSharpSnapshotGenerator.cs
@@ -707,8 +707,7 @@ protected virtual void GenerateComplexPropertyAnnotations(
if (typeAnnotations.ContainsKey(RelationalAnnotationNames.ContainerColumnName)
&& !typeAnnotations.ContainsKey(RelationalAnnotationNames.ContainerColumnType))
{
- var containerColumnType = property.ComplexType.GetContainerColumnType()
- ?? Dependencies.RelationalTypeMappingSource.FindMapping(typeof(JsonTypePlaceholder))?.StoreType;
+ var containerColumnType = property.ComplexType.GetContainerColumnType();
if (containerColumnType != null)
{
typeAnnotations[RelationalAnnotationNames.ContainerColumnType] = new Annotation(
@@ -921,8 +920,7 @@ protected virtual void GenerateEntityTypeAnnotations(
if (annotations.ContainsKey(RelationalAnnotationNames.ContainerColumnName)
&& !annotations.ContainsKey(RelationalAnnotationNames.ContainerColumnType))
{
- var containerColumnType = entityType.GetContainerColumnType()
- ?? Dependencies.RelationalTypeMappingSource.FindMapping(typeof(JsonTypePlaceholder))?.StoreType;
+ var containerColumnType = entityType.GetContainerColumnType();
if (containerColumnType != null)
{
annotations[RelationalAnnotationNames.ContainerColumnType] = new Annotation(
diff --git a/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs b/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs
index b5ee748ab77..89b67725b3a 100644
--- a/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalTypeBaseExtensions.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.EntityFrameworkCore.Internal;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
// ReSharper disable once CheckNamespace
#pragma warning disable IDE0130 // Namespace does not match folder structure
@@ -416,11 +417,32 @@ public static void SetContainerColumnName(this IMutableTypeBase typeBase, string
/// The type.
/// The database column type.
public static string? GetContainerColumnType(this IReadOnlyTypeBase typeBase)
- => typeBase.FindAnnotation(RelationalAnnotationNames.ContainerColumnType)?.Value is string columnName
- ? columnName
- : typeBase is IReadOnlyEntityType entityType
- ? entityType.FindOwnership()?.PrincipalEntityType.GetContainerColumnType()
- : ((IReadOnlyComplexType)typeBase).ComplexProperty.DeclaringType.GetContainerColumnType();
+ {
+ if (typeBase.FindAnnotation(RelationalAnnotationNames.ContainerColumnType)?.Value is string columnType)
+ {
+ return columnType;
+ }
+
+ var parentType = typeBase is IReadOnlyEntityType entityType
+ ? entityType.FindOwnership()?.PrincipalEntityType.GetContainerColumnType()
+ : ((IReadOnlyComplexType)typeBase).ComplexProperty.DeclaringType.GetContainerColumnType();
+
+ if (parentType != null)
+ {
+ return parentType;
+ }
+
+ if (typeBase.IsMappedToJson()
+#pragma warning disable EF1001 // Internal EF Core API usage.
+ && (typeBase.Model is not Model model || model.IsReadOnly))
+#pragma warning restore EF1001 // Internal EF Core API usage.
+ {
+ return ((IRelationalTypeMappingSource)((IModel)typeBase.Model).GetModelDependencies().TypeMappingSource)
+ .FindMapping(typeof(JsonTypePlaceholder))?.StoreType;
+ }
+
+ return null;
+ }
///
/// Sets the type of the container column to which the type is mapped.
diff --git a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
index 21c3f3d9cbc..9d6238784dd 100644
--- a/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
+++ b/test/EFCore.Relational.Tests/Metadata/RelationalModelTest.cs
@@ -3053,6 +3053,60 @@ public void Complex_collection_container_column_type_is_used_in_relational_model
Assert.Equal("some_json_mapping", column.StoreType);
}
+ [ConditionalFact]
+ public void Complex_property_gets_default_container_column_type_when_not_set_explicitly()
+ {
+ var modelBuilder = CreateConventionModelBuilder();
+
+ modelBuilder.Entity(eb =>
+ {
+ eb.ComplexProperty(
+ e => e.ComplexProperty, cb =>
+ {
+ cb.ToJson("complex_data");
+ });
+ });
+
+ var model = Finalize(modelBuilder);
+
+ var entityType = model.Model.FindEntityType(typeof(EntityWithComplexProperty));
+ var complexProperty = entityType.GetComplexProperties().Single();
+ var complexType = complexProperty.ComplexType;
+
+ Assert.Equal("some_json_mapping", complexType.GetContainerColumnType());
+
+ var table = entityType.GetTableMappings().Single().Table;
+ var column = table.Columns.Single(c => c.Name == "complex_data");
+ Assert.Equal("some_json_mapping", column.StoreType);
+ }
+
+ [ConditionalFact]
+ public void Complex_collection_gets_default_container_column_type_when_not_set_explicitly()
+ {
+ var modelBuilder = CreateConventionModelBuilder();
+
+ modelBuilder.Entity(eb =>
+ {
+ eb.ComplexCollection(
+ e => e.ComplexCollection, cb =>
+ {
+ cb.ToJson("collection_data");
+ });
+ });
+
+ var model = Finalize(modelBuilder);
+
+ var entityType = model.Model.FindEntityType(typeof(EntityWithComplexCollection));
+ var complexProperty = entityType.GetComplexProperties().Single();
+ var complexType = complexProperty.ComplexType;
+
+ Assert.Equal("some_json_mapping", complexType.GetContainerColumnType());
+
+ var table = entityType.GetTableMappings().Single().Table;
+ var column = table.Columns.Single(c => c.Name == "collection_data");
+ Assert.Equal("some_json_mapping", column.StoreType);
+ }
+
[ConditionalFact]
public void Can_use_relational_model_with_functions()
{