diff --git a/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs b/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs index 2cbdaa588..e484cb56e 100644 --- a/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs +++ b/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs @@ -14,8 +14,11 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal; /// doing so can result in application failures when updating to a new Entity Framework Core release. /// #pragma warning disable EF1001 // Internal EF Core API usage. -public class NpgsqlCSharpRuntimeAnnotationCodeGenerator : RelationalCSharpRuntimeAnnotationCodeGenerator +public class NpgsqlCSharpRuntimeAnnotationCodeGenerator + : RelationalCSharpRuntimeAnnotationCodeGenerator, ICSharpRuntimeAnnotationCodeGenerator { + private int _typeMappingNestingCount; + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -42,8 +45,31 @@ public override bool Create( ValueComparer? keyValueComparer = null, ValueComparer? providerValueComparer = null) { - var result = base.Create(typeMapping, parameters, valueComparer, keyValueComparer, providerValueComparer); + _typeMappingNestingCount++; + try + { + var result = base.Create(typeMapping, parameters, valueComparer, keyValueComparer, providerValueComparer); + AddNpgsqlTypeMappingTweaks(typeMapping, parameters); + return result; + } + finally + { + _typeMappingNestingCount--; + } + } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [EntityFrameworkInternal] + protected virtual void AddNpgsqlTypeMappingTweaks( + CoreTypeMapping typeMapping, + CSharpRuntimeAnnotationCodeGeneratorParameters parameters) + { var mainBuilder = parameters.MainBuilder; var npgsqlDbTypeBasedDefaultInstance = typeMapping switch @@ -57,6 +83,8 @@ public override bool Create( if (npgsqlDbTypeBasedDefaultInstance is not null) { + CheckElementTypeMapping(); + var npgsqlDbType = ((INpgsqlTypeMapping)typeMapping).NpgsqlDbType; if (npgsqlDbType != npgsqlDbTypeBasedDefaultInstance.NpgsqlDbType) @@ -83,6 +111,8 @@ public override bool Create( switch (typeMapping) { case NpgsqlEnumTypeMapping enumTypeMapping: + CheckElementTypeMapping(); + var code = Dependencies.CSharpHelper; mainBuilder.AppendLine(";"); @@ -119,6 +149,8 @@ public override bool Create( case NpgsqlRangeTypeMapping rangeTypeMapping: { + CheckElementTypeMapping(); + var defaultInstance = NpgsqlRangeTypeMapping.Default; var npgsqlDbTypeDifferent = rangeTypeMapping.NpgsqlDbType != defaultInstance.NpgsqlDbType; @@ -154,7 +186,14 @@ public override bool Create( } } - return result; + void CheckElementTypeMapping() + { + if (_typeMappingNestingCount > 1) + { + throw new NotSupportedException( + $"Non-default Npgsql type mappings ('{typeMapping.GetType().Name}' with store type '{(typeMapping as RelationalTypeMapping)?.StoreType}') aren't currently supported as element type mappings, see https://github.com/npgsql/efcore.pg/issues/3366."); + } + } } ///