diff --git a/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs b/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs
index f8a1519c3..9d26dfce5 100644
--- a/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs
+++ b/src/EFCore.PG/Design/Internal/NpgsqlCSharpRuntimeAnnotationCodeGenerator.cs
@@ -3,6 +3,7 @@
using Microsoft.EntityFrameworkCore.Design.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata.Internal;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Design.Internal;
@@ -28,6 +29,109 @@ public NpgsqlCSharpRuntimeAnnotationCodeGenerator(
{
}
+ ///
+ /// 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.
+ ///
+ public override bool Create(
+ CoreTypeMapping typeMapping,
+ CSharpRuntimeAnnotationCodeGeneratorParameters parameters,
+ ValueComparer? valueComparer = null,
+ ValueComparer? keyValueComparer = null,
+ ValueComparer? providerValueComparer = null)
+ {
+ var result = base.Create(typeMapping, parameters, valueComparer, keyValueComparer, providerValueComparer);
+
+ var mainBuilder = parameters.MainBuilder;
+
+ var npgsqlDbTypeBasedDefaultInstance = typeMapping switch
+ {
+ NpgsqlStringTypeMapping => NpgsqlStringTypeMapping.Default,
+ NpgsqlULongTypeMapping => NpgsqlULongTypeMapping.Default,
+ // NpgsqlMultirangeTypeMapping => NpgsqlMultirangeTypeMapping.Default,
+ _ => (INpgsqlTypeMapping?)null
+ };
+
+ if (npgsqlDbTypeBasedDefaultInstance is not null)
+ {
+ var npgsqlDbType = ((INpgsqlTypeMapping)typeMapping).NpgsqlDbType;
+
+ if (npgsqlDbType != npgsqlDbTypeBasedDefaultInstance.NpgsqlDbType)
+ {
+ mainBuilder.AppendLine(";");
+
+ mainBuilder.Append(
+ $"{parameters.TargetName}.TypeMapping = (({typeMapping.GetType().Name}){parameters.TargetName}.TypeMapping).Clone(npgsqlDbType: ");
+
+ mainBuilder
+ .Append(nameof(NpgsqlTypes))
+ .Append(".")
+ .Append(nameof(NpgsqlDbType))
+ .Append(".")
+ .Append(npgsqlDbType.ToString());
+
+ mainBuilder
+ .Append(")")
+ .DecrementIndent();
+ }
+
+ }
+
+ switch (typeMapping)
+ {
+#pragma warning disable CS0618 // NpgsqlConnection.GlobalTypeMapper is obsolete
+ case NpgsqlEnumTypeMapping enumTypeMapping:
+ if (enumTypeMapping.NameTranslator != NpgsqlConnection.GlobalTypeMapper.DefaultNameTranslator)
+ {
+ throw new NotSupportedException(
+ "Mapped enums are only supported in the compiled model if they use the default name translator");
+ }
+ break;
+#pragma warning restore CS0618
+
+ case NpgsqlRangeTypeMapping rangeTypeMapping:
+ {
+ var defaultInstance = NpgsqlRangeTypeMapping.Default;
+
+ var npgsqlDbTypeDifferent = rangeTypeMapping.NpgsqlDbType != defaultInstance.NpgsqlDbType;
+ var subtypeTypeMappingIsDifferent = rangeTypeMapping.SubtypeMapping != defaultInstance.SubtypeMapping;
+
+ if (npgsqlDbTypeDifferent || subtypeTypeMappingIsDifferent)
+ {
+ mainBuilder.AppendLine(";");
+
+ mainBuilder.AppendLine(
+ $"{parameters.TargetName}.TypeMapping = ((NpgsqlRangeTypeMapping){parameters.TargetName}.TypeMapping).Clone(")
+ .IncrementIndent();
+
+ mainBuilder
+ .Append("npgsqlDbType: ")
+ .Append(nameof(NpgsqlTypes))
+ .Append(".")
+ .Append(nameof(NpgsqlDbType))
+ .Append(".")
+ .Append(rangeTypeMapping.NpgsqlDbType.ToString())
+ .AppendLine(",");
+
+ mainBuilder.Append("subtypeTypeMapping: ");
+
+ Create(rangeTypeMapping.SubtypeMapping, parameters);
+
+ mainBuilder
+ .Append(")")
+ .DecrementIndent();
+ }
+
+ break;
+ }
+
+ }
+
+ return result;
+ }
+
///
public override void Generate(IModel model, CSharpRuntimeAnnotationCodeGeneratorParameters parameters)
{
diff --git a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlEnumTypeMapping.cs b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlEnumTypeMapping.cs
index c99dd5e91..94f1ead19 100644
--- a/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlEnumTypeMapping.cs
+++ b/src/EFCore.PG/Storage/Internal/Mapping/NpgsqlEnumTypeMapping.cs
@@ -11,9 +11,6 @@ namespace Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
///
public class NpgsqlEnumTypeMapping : RelationalTypeMapping
{
- private readonly ISqlGenerationHelper _sqlGenerationHelper;
- private readonly INpgsqlNameTranslator _nameTranslator;
-
///
/// Translates the CLR member value to the PostgreSQL value label.
///
@@ -25,14 +22,25 @@ public class NpgsqlEnumTypeMapping : RelationalTypeMapping
/// 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.
///
- public NpgsqlEnumTypeMapping(
- string storeType,
- string? storeTypeSchema,
- Type enumType,
- ISqlGenerationHelper sqlGenerationHelper,
- INpgsqlNameTranslator? nameTranslator = null)
+ public static NpgsqlEnumTypeMapping Default { get; } = new();
+
+ ///
+ /// 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.
+ ///
+ public virtual INpgsqlNameTranslator NameTranslator { get; }
+
+ ///
+ /// 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.
+ ///
+ public NpgsqlEnumTypeMapping(string storeType, Type enumType, INpgsqlNameTranslator? nameTranslator = null)
: base(
- sqlGenerationHelper.DelimitIdentifier(storeType, storeTypeSchema),
+ storeType,
enumType,
jsonValueReaderWriter: (JsonValueReaderWriter?)Activator.CreateInstance(
typeof(JsonPgEnumReaderWriter<>).MakeGenericType(enumType)))
@@ -46,8 +54,7 @@ public NpgsqlEnumTypeMapping(
nameTranslator ??= NpgsqlConnection.GlobalTypeMapper.DefaultNameTranslator;
#pragma warning restore CS0618
- _nameTranslator = nameTranslator;
- _sqlGenerationHelper = sqlGenerationHelper;
+ NameTranslator = nameTranslator;
_members = CreateValueMapping(enumType, nameTranslator);
}
@@ -59,15 +66,24 @@ public NpgsqlEnumTypeMapping(
///
protected NpgsqlEnumTypeMapping(
RelationalTypeMappingParameters parameters,
- ISqlGenerationHelper sqlGenerationHelper,
INpgsqlNameTranslator nameTranslator)
: base(parameters)
{
- _nameTranslator = nameTranslator;
- _sqlGenerationHelper = sqlGenerationHelper;
+ NameTranslator = nameTranslator;
_members = CreateValueMapping(parameters.CoreParameters.ClrType, nameTranslator);
}
+ // This constructor exists only to support the static Default property above, which is necessary to allow code generation for compiled
+ // models. The constructor creates a completely blank type mapping, which will get cloned with all the correct details.
+ private NpgsqlEnumTypeMapping()
+ : base("some_enum", typeof(int))
+ {
+#pragma warning disable CS0618 // NpgsqlConnection.GlobalTypeMapper is obsolete
+ NameTranslator = NpgsqlConnection.GlobalTypeMapper.DefaultNameTranslator;
+#pragma warning restore CS0618
+ _members = null!;
+ }
+
///
/// 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
@@ -75,7 +91,7 @@ protected NpgsqlEnumTypeMapping(
/// doing so can result in application failures when updating to a new Entity Framework Core release.
///
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
- => new NpgsqlEnumTypeMapping(parameters, _sqlGenerationHelper, _nameTranslator);
+ => new NpgsqlEnumTypeMapping(parameters, NameTranslator);
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -98,12 +114,31 @@ private static Dictionary