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

如何在.NET 6中读取PostgreSQL函数返回的<unnamed portal 1>数据?

从PostgreSQL的<unnamed portal 1>中读取数据的解决方案

背景信息

PostgreSQL函数

CREATE OR REPLACE FUNCTION public.fn_test() 
RETURNS refcursor AS $$
DECLARE
    ref1 refcursor;
BEGIN

OPEN ref1 FOR 
    Select * from public.testTable;

RETURN ref1;
END;
$$ LANGUAGE plpgsql;

C# .NET 6代码

string connString = String.Format("Server={0};Database={1};User Id={2};Password={3};Port={4}", Host, "testDB", Username, Password, Port);
NpgsqlConnection pgCon = new NpgsqlConnection(connString);
pgCon.Open();
string strCmd = @"select * from public.fn_test();";
NpgsqlCommand pgCmd = new NpgsqlCommand(strCmd, pgCon);
NpgsqlDataReader pgDr = pgCmd.ExecuteReader(); //返回<unnamed portal 1>

问题

调用上述函数后,ExecuteReader()返回了<unnamed portal 1>,如何从中读取数据?

环境信息:

  • PostgreSQL版本:14.5
  • .NET版本:6
  • Visual Studio版本:2022

解决方案

要读取refcursor返回的结果,需遵循PostgreSQL的游标机制,具体实现方式如下:

方式一:使用命名游标(推荐)

修改PostgreSQL函数,指定明确的游标名称,避免依赖系统生成的无名游标:

CREATE OR REPLACE FUNCTION public.fn_test() 
RETURNS refcursor AS $$
DECLARE
    ref1 refcursor := 'my_test_cursor'; -- 指定自定义游标名称
BEGIN
    OPEN ref1 FOR 
        Select * from public.testTable;
    RETURN ref1;
END;
$$ LANGUAGE plpgsql;

对应调整C#代码,通过游标名称执行FETCH命令读取数据:

string connString = String.Format("Server={0};Database={1};User Id={2};Password={3};Port={4}", Host, "testDB", Username, Password, Port);
// 使用using语句自动释放资源
using (NpgsqlConnection pgCon = new NpgsqlConnection(connString))
{
    pgCon.Open();
    // 游标必须在事务上下文内操作
    using (var transaction = pgCon.BeginTransaction())
    {
        string strCmd = @"select * from public.fn_test();";
        NpgsqlCommand pgCmd = new NpgsqlCommand(strCmd, pgCon, transaction);
        // 获取函数返回的游标名称
        var cursorName = pgCmd.ExecuteScalar().ToString();
        
        // 执行FETCH命令读取游标内所有数据
        var fetchCmd = new NpgsqlCommand($"FETCH ALL FROM {cursorName};", pgCon, transaction);
        using (NpgsqlDataReader pgDr = fetchCmd.ExecuteReader())
        {
            while (pgDr.Read())
            {
                // 处理单条数据示例:读取指定列值
                var targetValue = pgDr["your_column_name"];
                // 此处编写业务逻辑
            }
        }
        transaction.Commit();
    }
}

方式二:直接读取无名游标

若不想修改PostgreSQL函数,可直接使用系统返回的<unnamed portal 1>名称执行FETCH,但该方式依赖PostgreSQL内部命名规则,稳定性较差:

string connString = String.Format("Server={0};Database={1};User Id={2};Password={3};Port={4}", Host, "testDB", Username, Password, Port);
using (NpgsqlConnection pgCon = new NpgsqlConnection(connString))
{
    pgCon.Open();
    using (var transaction = pgCon.BeginTransaction())
    {
        string strCmd = @"select * from public.fn_test();";
        NpgsqlCommand pgCmd = new NpgsqlCommand(strCmd, pgCon, transaction);
        // 先执行函数打开游标,关闭临时DataReader
        pgCmd.ExecuteReader().Close();
        
        // 通过无名游标名称读取数据
        var fetchCmd = new NpgsqlCommand("FETCH ALL FROM \"<unnamed portal 1>\";", pgCon, transaction);
        using (NpgsqlDataReader pgDr = fetchCmd.ExecuteReader())
        {
            while (pgDr.Read())
            {
                // 处理数据逻辑
            }
        }
        transaction.Commit();
    }
}

关键注意事项

  • 游标操作必须在事务上下文中执行,PostgreSQL不允许在事务外使用游标。
  • 始终使用using语句管理数据库连接、命令和数据阅读器,避免资源泄漏。
  • 优先选择命名游标方案,避免依赖系统生成的无名游标名称,提升代码稳定性。

内容的提问来源于stack exchange,提问作者Shankar Naru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:50:16