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

Postgres ENUM类型首次运行时无法被Dapper识别的问题求助

Postgres ENUM 同会话创建后查询报错的解决方案

问题原因

Npgsql在连接初始化时会获取并缓存数据库的元数据(包括所有类型信息)。当你在同一会话中创建新的ENUM类型后,Npgsql本地的缓存不会自动刷新,导致后续查询时无法识别这个刚创建的ENUM,从而抛出类型未找到的错误。第二次运行时,连接初始化时ENUM已经存在,缓存里有对应的类型信息,所以查询正常。

解决方案

方法1:手动刷新类型缓存

在创建ENUM和表之后,调用NpgsqlConnection的ReloadTypesAsync方法,强制刷新本地的类型缓存,让Npgsql获取最新的数据库类型信息。

修改后的代码示例:

using Dapper;
using Npgsql;

var connection = new NpgsqlConnection("Host=127.0.0.1;Port=5432;User ID=postgres;Password=password;Database=messaging;Include Error Detail=true;");
await connection.OpenAsync();

var tableCommand = new NpgsqlCommand()
{
    Connection = connection,
    CommandText = """
        CREATE TYPE message_type AS ENUM ('sms', 'email');
        CREATE TABLE message (
            id SERIAL PRIMARY KEY,
            type message_type NOT NULL
        );
        """
};

await tableCommand.ExecuteNonQueryAsync();

// 关键步骤:刷新数据库类型缓存
await connection.ReloadTypesAsync();

var queryCommand = new NpgsqlCommand()
{
    Connection = connection,
    CommandText = """
        SELECT id, type
        FROM message;
        """
};

var reader = await queryCommand.ExecuteReaderAsync();
var parser = reader.GetRowParser<Message>();

class Message
{
    public int Id { get; set; }
    public string? Type { get; set; }
}

方法2:拆分连接执行操作

创建ENUM和表用一个独立连接,查询用另一个新连接。新连接初始化时会自动加载最新的数据库元数据,自然能识别已创建的ENUM。

代码示例:

using Dapper;
using Npgsql;

// 第一个连接:负责创建类型和表
using (var createConnection = new NpgsqlConnection("Host=127.0.0.1;Port=5432;User ID=postgres;Password=password;Database=messaging;Include Error Detail=true;"))
{
    await createConnection.OpenAsync();
    var tableCommand = new NpgsqlCommand()
    {
        Connection = createConnection,
        CommandText = """
            CREATE TYPE message_type AS ENUM ('sms', 'email');
            CREATE TABLE message (
                id SERIAL PRIMARY KEY,
                type message_type NOT NULL
            );
            """
    };
    await tableCommand.ExecuteNonQueryAsync();
}

// 第二个连接:执行查询操作
using (var queryConnection = new NpgsqlConnection("Host=127.0.0.1;Port=5432;User ID=postgres;Password=password;Database=messaging;Include Error Detail=true;"))
{
    await queryConnection.OpenAsync();
    var queryCommand = new NpgsqlCommand()
    {
        Connection = queryConnection,
        CommandText = """
            SELECT id, type
            FROM message;
            """
    };
    var reader = await queryCommand.ExecuteReaderAsync();
    var parser = reader.GetRowParser<Message>();
}

class Message
{
    public int Id { get; set; }
    public string? Type { get; set; }
}

方法3:提前注册ENUM类型

如果提前知道ENUM的定义,可以在打开连接前,用Npgsql的全局类型映射器注册对应的枚举类型,这样即使是同会话创建,也能正确识别。

代码示例:

using Dapper;
using Npgsql;

// 提前注册ENUM与C#枚举的映射
NpgsqlConnection.GlobalTypeMapper.MapEnum<MessageType>();

var connection = new NpgsqlConnection("Host=127.0.0.1;Port=5432;User ID=postgres;Password=password;Database=messaging;Include Error Detail=true;");
await connection.OpenAsync();

var tableCommand = new NpgsqlCommand()
{
    Connection = connection,
    CommandText = """
        CREATE TYPE message_type AS ENUM ('sms', 'email');
        CREATE TABLE message (
            id SERIAL PRIMARY KEY,
            type message_type NOT NULL
        );
        """
};

await tableCommand.ExecuteNonQueryAsync();

var queryCommand = new NpgsqlCommand()
{
    Connection = connection,
    CommandText = """
        SELECT id, type
        FROM message;
        """
};

var reader = await queryCommand.ExecuteReaderAsync();
var parser = reader.GetRowParser<Message>();

// 定义与Postgres ENUM对应的C#枚举
public enum MessageType
{
    sms,
    email
}

class Message
{
    public int Id { get; set; }
    public MessageType Type { get; set; }
}

适用场景说明

  • 方法1适合需要在同一会话中完成创建和查询的场景,操作简单直接。
  • 方法2适合迁移脚本等不需要保持会话连续性的场景,逻辑清晰。
  • 方法3适合提前明确ENUM定义的场景,能获得更强的类型安全性。

内容的提问来源于stack exchange,提问作者Rick de Water

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 13:20:54