如何通过在 npgsql 中调用存储过程来获取游标数据

how can I get cursor data with calling stored procedure in npgsql

我查看了 www.npgsql.org 中的资料,但找不到解决问题的方法...

Table, PostgreSQL

[City], [State]
"Austin", "TX"
"Houston", "TX"
"Los Angeles", "CA"
"San Diego", "CA"
"San Fransisco";"CA"
"St.Louis", "MO"

函数(存储过程),PostgreSQL

-- Procedure that returns a single result set (cursor) 
   CREATE OR REPLACE FUNCTION show_cities() RETURNS refcursor AS $$
    DECLARE
      ref refcursor;
    BEGIN
      OPEN ref FOR SELECT city, state FROM cities;
      RETURN ref;                                 
    END;
    $$ LANGUAGE plpgsql;

代码,C#

using (NpgsqlConnection conn = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["dbConnection"].ConnectionString))
{
    conn.Open();
    using (NpgsqlTransaction tran = conn.BeginTransaction())
    {
        using (var command = new NpgsqlCommand("show_cities", conn))
        {
            command.Transaction = tran;
            command.CommandType = CommandType.StoredProcedure;
            NpgsqlDataReader dr = command.ExecuteReader();

            while (dr.Read())
                str += dr.GetValue(0);

            dr.Close();
        }
        tran.Commit();
    }
}

这个 returns "unnamed portal 1" 是要获取的游标而不是数据, 有什么方法可以将其转换为 Austin, Houston, Los Angeles... 这样的数据?

互联网上有一些关于此的帖子,但我不确定我做错了什么。

(已添加) 我发现这发生在 npgsql ver3.x 中,而在 ver2.x 中它与我的代码一起工作正常。获取游标的用法有任何变化吗?

(参考) http://www.sqlines.com/postgresql/npgsql_cs_result_sets

Npgsql 2.x 有一个特性,它可以自动 "dereferenced" 从函数中 return 游标。此功能已从 Npgsql 3.0 中删除;我们在 3.0 的迁移节点中提到了这一点,讨论在 this issue 中。由于游标只是 returned 而不是取消引用,Npgsql returns 游标名称本身(未命名的门户 1);您现在可以通过发送 FETCH

从此查询中获取结果

然而,如前所述,将单个 SELECT 包装在函数中没有多大意义。如果您确实需要编写一个 return 是 单个 结果集的函数,请将其设为 return SETOF 或 TABLE 而不是游标:CREATE FUNCTION ... RETURNS TABLE (column_name column_type [, ...])。除了更简单和更清晰之外,这也更有效,因为查询结果是直接 returned(取消引用游标涉及另一个数据库往返)。

请参阅 PostgreSQL docs 了解有关如何定义函数的更多信息 returning table。

在 Shay 的帮助下,我弄清楚了如何在删除“dereferenced”功能后在 v3.x 中获取光标。 我认为这方面的好例子不多,希望这可以帮助人们节省搜索示例的时间。

您可以在 npgsql 中执行此操作 ver3.x

1. CommandType.StoredProcedure(游标名称未定义)

conn.Open();
NpgsqlTransaction tran = conn.BeginTransaction();

NpgsqlCommand command = new NpgsqlCommand("show_cities", conn);
command.CommandType = CommandType.StoredProcedure;
command.ExecuteNonQuery();

command.CommandText = "fetch all in \"<unnamed portal 1>\"";
command.CommandType = CommandType.Text;

NpgsqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
    // do what you want with data, convert this to json or...
    Console.WriteLine(dr[0]);
}
dr.Close();

tran.Commit();
conn.Close();

2。 CommandType.StoredProcedure(已定义游标名称)

conn.Open();
NpgsqlTransaction tran = conn.BeginTransaction();

NpgsqlCommand command = new NpgsqlCommand("select show_cities(@ref)", conn);
command.CommandType = CommandType.Text;
NpgsqlParameter p = new NpgsqlParameter();
p.ParameterName = "@ref";
p.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Refcursor;
p.Direction = ParameterDirection.InputOutput;
p.Value = "ref";
command.Parameters.Add(p);
command.ExecuteNonQuery();

command.CommandText = "fetch all in \"ref\"";
command.CommandType = CommandType.Text;

NpgsqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
    // do what you want with data, convert this to json or...
    Console.WriteLine(dr[0]);
}
dr.Close();

tran.Commit();
conn.Close();

3。 CommandType.Text(已定义游标名称)

conn.Open();
NpgsqlTransaction tran = conn.BeginTransaction();

NpgsqlCommand command = new NpgsqlCommand("select show_cities(@ref)", conn);
command.CommandType = CommandType.Text;
NpgsqlParameter p = new NpgsqlParameter();
p.ParameterName = "@ref";
p.NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Refcursor;
p.Direction = ParameterDirection.InputOutput;
p.Value = "ref";
command.Parameters.Add(p);
command.ExecuteNonQuery();

command.CommandText = "fetch all in \"ref\"";
command.CommandType = CommandType.Text;

NpgsqlDataReader dr = command.ExecuteReader();
while (dr.Read())
{
    // do what you want with data, convert this to json or...
    Console.WriteLine(dr[0]);
}
dr.Close();

tran.Commit();
conn.Close();

(参考 v2.x)http://www.sqlines.com/postgresql/npgsql_cs_result_sets

这是为了便于理解的示例,所以如果您希望您的函数 return 单个结果集,那么请考虑 return 而不是 returning cursor =] table 正如@Shay 建议的那样,或者创建一个 view 而不是 @CeOnSql 建议的 function

谢谢!

我有以下 Npgsql 2.2.7 版本的工作代码:

 private static DataSet ExecuteFunction(string functionName)
    {
        DataSet ds = new DataSet();

        var conn = new NpgsqlConnection("replace with connection string");
        conn.Open();
        var tran = conn.BeginTransaction();
        var cmd = new NpgsqlCommand(functionName, conn);
        cmd.CommandType = CommandType.StoredProcedure;

        NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd);
        da.Fill(ds);

        //foreach (DataRow r in ds.Tables[0].Rows)
        //{
        //    Console.WriteLine("{0}", r[0]);
        //}

        tran.Commit();
        conn.Close();
        return ds;
    }