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

如何使用Npgsql从PostgreSQL存储过程的refcursor参数获取数据

解决PostgreSQL存储过程INOUT refcursor参数调用报错问题

问题原因

你遇到的34000: cursor "p_refcur" does not exist错误,核心原因有两个:

  • PostgreSQL的游标是事务绑定的,默认执行ExecuteNonQuery()后,隐式事务会自动提交,游标随即被销毁。
  • 硬编码使用传入的游标名p_refcur无效,存储过程返回的INOUT参数实际返回的是PostgreSQL内部生成的游标标识,并非你传入的字面名称。

解决方案

无需修改存储过程,只需调整C#调用代码,保留事务上下文并读取存储过程返回的实际游标值:

修正后的代码示例

using (var dataSource = NpgsqlDataSource.Create(this.connectionString))
{
    // 显式开启连接与事务,维持游标生命周期
    using (var conn = dataSource.OpenConnection())
    using (var tx = conn.BeginTransaction())
    {
        using (var command = conn.CreateCommand())
        {
            command.CommandType = CommandType.StoredProcedure;
            command.CommandText = "myschema_dbo.usp_getcustomers";
            command.Transaction = tx;

            // 添加输入参数
            command.Parameters.Add(new NpgsqlParameter()
            {
                ParameterName = "par_includeinactive",
                NpgsqlDbType = NpgsqlDbType.Numeric,
                Direction = ParameterDirection.Input,
                Value = 1
            });

            // 定义游标参数,无需预赋值
            var refCurParam = new NpgsqlParameter()
            {
                ParameterName = "p_refcur",
                NpgsqlDbType = NpgsqlDbType.Refcursor,
                Direction = ParameterDirection.InputOutput
            };
            command.Parameters.Add(refCurParam);

            // 执行存储过程
            command.ExecuteNonQuery();

            // 从输出参数获取实际游标名称
            var cursorName = refCurParam.Value.ToString();

            // 构造FETCH命令并清空原有参数
            command.CommandText = $"fetch all in \"{cursorName}\"";
            command.CommandType = CommandType.Text;
            command.Parameters.Clear();

            // 读取数据
            using (var reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    // 处理数据逻辑示例
                    var customerName = reader.GetString(reader.GetOrdinal("customername"));
                    var isActive = reader.GetBoolean(reader.GetOrdinal("isactive"));
                    var email = reader.GetString(reader.GetOrdinal("emailaddress"));
                }
            }

            // 提交事务
            tx.Commit();
        }
    }
}

关键修改点

  • 显式开启事务:确保游标在数据读取全程保持有效,避免隐式提交导致游标销毁。
  • 不预赋值游标参数:让PostgreSQL自动生成正确的游标标识,执行后从输出参数读取实际名称。
  • 执行FETCH前清空参数:避免原有参数残留引发SQL语法错误。

额外说明

这套逻辑可批量适配所有自动生成的、带INOUT refcursor参数的存储过程,无需逐个修改数据库端代码。

内容的提问来源于stack exchange,提问作者Jonathan Lawson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 20:25:10