Postgres ENUM 类型在第一次运行时对 dapper 不可见

问题描述 投票:0回答:2

我在使用 Postgres 枚举时遇到了一个奇怪的问题,尝试使用

ENUM
查询表时遇到错误,但前提是
CREATE
命令在同一会话期间运行。我不知道为什么会发生这种情况,这使得运行迁移脚本变得非常困难,因为我现在必须运行应用程序两次才能一切正常。

认为这是某种缓存问题,我尝试关闭连接池,但这似乎也不起作用。

它很容易重现,所以我制作了一个代码示例:

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
        );
        """
};

// Comment this line on a second run
await tableCommand.ExecuteNonQueryAsync();

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

var reader = await queryCommand.ExecuteReaderAsync();
// The offending line
var parser = reader.GetRowParser<Message>();

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

第一次运行时会产生以下错误:

System.InvalidCastException: 'Reading as 'System.Object' is not supported for fields having DataTypeName '.<unknown>''

Inner Exception
ArgumentException: A PostgreSQL type with the oid '0' was not found in the current database info

在第二次运行时(注释掉创建命令时),我没有收到任何错误,一切都按预期进行。第一次运行时几乎看不到枚举存在,但第二次一切都很好,因为在建立连接时它已经存在了。

我正在使用所有内容的最新版本(在撰写本文时):

  • Postgres 16.1
  • .NET 8
  • 短小精悍2.1.24
  • Npgsql 8.0.1
c# dapper npgsql
2个回答
0
投票

Dapper 对 postgresql 枚举一无所知;我只能假设这是在 Npgsql 内部处理的,Npgsql 在需要时构建已知类型的缓存,因此如果您添加类型:它不会立即知道它。请注意,Dapper.AOT 正在添加更多枚举支持(目前还不存在),它将使用不同的 API,而不是

object
API;这可能会改变 Npgsql 的工作方式,希望变得更好!


0
投票

您必须使用

await connection.ReloadTypesAsync();
重新加载在命令中创建的新类型。

这是一个示例,使用 Dapper 而不是命令,但您可以简单地在代码中插入重新加载类型命令:

await connection.ExecuteAsync("""
    CREATE TYPE message_type AS ENUM ('sms', 'email');
    CREATE TABLE message (
        id SERIAL PRIMARY KEY,
        type message_type NOT NULL
    );
    """);

await connection.ReloadTypesAsync(); // add this to your code

var parser = await connection.QueryAsync<Message>("""
       SELECT id, type
       FROM message;
       """);  

NpgsqlConnection 中记录了此方法刷新连接中加载的类型的缓存。

© www.soinside.com 2019 - 2024. All rights reserved.