You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core+Npgsql无法将枚举映射为PostgreSQL枚举类型(传为整数)

EF Core 映射枚举到PostgreSQL自定义枚举失败问题

问题现象

尝试通过EF Core将模型中的枚举映射到PostgreSQL自定义枚举类型,但EF Core始终将枚举值以整数而非PostgreSQL枚举类型发送,导致数据库报错。

枚举定义

public enum EventType
{
    Purchase,
    Signup,
    OfferTrading
}

DbContext配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);

    modelBuilder.HasPostgresEnum<EventType>(
        name: "event_type",
        nameTranslator: new NpgsqlSnakeCaseNameTranslator());

    // 也曾尝试:
    // modelBuilder.HasPostgresEnum<EventType>("event_type");
    // modelBuilder.HasPostgresEnum<EventType>();

    base.OnModelCreating(modelBuilder);
}

NpgsqlDataSource配置

var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);

dataSourceBuilder.MapEnum<EventType>(
    pgName: "event_type",
    nameTranslator: new NpgsqlSnakeCaseNameTranslator());

// 也曾尝试:
// dataSourceBuilder.MapEnum<EventType>("event_type");
// dataSourceBuilder.MapEnum<EventType>();

var dataSource = dataSourceBuilder.Build();

services.AddSingleton(dataSource);

services.AddDbContext<AppDbContext>((sp, options) =>
    options.UseNpgsql(
            sp.GetRequiredService<NpgsqlDataSource>(),
            b => b.MigrationsAssembly("*******.Infrastructure"))
        .UseSnakeCaseNamingConvention()
        .EnableSensitiveDataLogging()
        .EnableDetailedErrors()
        .AddInterceptors(new AuditInterceptor()));

设计时配置

已实现带有相同配置的IDesignTimeDbContextFactory<>。

实体配置

builder.Property(c => c.EventType)
    .HasColumnType("event_type")
    .IsRequired();

曾尝试在此处添加字符串转换器,但仅将错误从integer改为text,仍未转换为event_type PostgreSQL类型。

迁移情况

初始迁移中枚举类型已正确创建(已确认存在于数据库):

migrationBuilder.AlterDatabase()
    .Annotation("Npgsql:Enum:event_type", "purchase,signup,offer_trading");

表定义中:

event_type = table.Column<int>(type: "event_type", nullable: false),

生成的SQL

插入数据时EF Core生成的SQL:

INSERT INTO campaigns (id, created_at, event_type, external_template_id, name, partner_id, priority, updated_at, validity_period_end, validity_period_start, contact_channels)
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10)

参数显示:

..., @p2 = '0', ...
// 预期应为:
@p2 = 'purchase' (DbType = event_type)

参数类型未设置为event_type,仅发送整数值;使用字符串转换器时发送字符串,但仍未设置正确的PostgreSQL枚举类型,错误依旧。

最终错误

PostgresException: 42804: column "event_type" is of type event_type but expression is of type integer

使用版本

  • .NET 10
  • EF Core 10
  • Npgsql.EntityFrameworkCore.PostgreSQL 10.0.1
  • Npgsql 10.0.2
  • PostgreSQL 18

未配置全局枚举转换(之前曾配置,现已移除)。

核心问题

EF Core + Npgsql如何正确绑定枚举为PostgreSQL枚举类型而非以整数或文本发送?还缺少哪些配置?


解决方案

1. 修复迁移中的列类型定义

迁移代码中table.Column<int>是核心问题,EF Core错误地将列类型标记为int,即使指定了type: "event_type"。手动修改迁移文件,将Column<int>改为Column<EventType>:

event_type = table.Column<EventType>(type: "event_type", nullable: false),

修改完成后重新应用迁移。

2. 调整枚举注册与实体配置的顺序

在OnModelCreating中,先注册PostgreSQL枚举,再应用实体配置。当前代码先加载实体配置后注册枚举,会导致实体配置无法感知到PostgreSQL枚举的存在,默认使用整数映射。调整顺序:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 先注册PostgreSQL枚举
    modelBuilder.HasPostgresEnum<EventType>(
        name: "event_type",
        nameTranslator: new NpgsqlSnakeCaseNameTranslator());

    // 再应用实体配置
    modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);

    base.OnModelCreating(modelBuilder);
}

3. 移除自定义转换器

不要为枚举添加字符串或其他自定义转换器,Npgsql会自动处理枚举与PostgreSQL自定义枚举的映射,手动添加转换器会覆盖默认行为。

4. 同步设计时工厂的配置顺序

确保IDesignTimeDbContextFactory中的配置逻辑与OnModelCreating一致,先注册枚举再加载实体配置。

5. 清理并重新生成迁移

若旧迁移存在遗留错误,删除旧迁移文件后重新生成:

dotnet ef migrations remove
dotnet ef migrations add InitialCreate
dotnet ef database update

内容的提问来源于stack exchange,提问作者Henrique Miranda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 10:27:01