C#和PostgreSQL

C#和PostgreSQL,c#,.net,sql,postgresql,ado.net,C#,.net,Sql,Postgresql,Ado.net,有人能给我举一个使用从PLSQL返回到C代码的游标的工作示例吗 我找到了许多示例,展示了如何用返回的数据填充数据集,但我找不到如何将光标与数据读取器一起使用,因此我得到了{unnamed portal} NpgsqlTransaction tr = (NpgsqlTransaction) Connection.BeginTransaction(); NpgsqlCommand cursCmd = new NpgsqlCommand("someStoredProcedure(:inRadius)"

有人能给我举一个使用从PLSQL返回到C代码的游标的工作示例吗

我找到了许多示例,展示了如何用返回的数据填充
数据集
,但我找不到如何将光标与
数据读取器
一起使用,因此我得到了
{unnamed portal}

NpgsqlTransaction tr = (NpgsqlTransaction) Connection.BeginTransaction();
NpgsqlCommand cursCmd = new NpgsqlCommand("someStoredProcedure(:inRadius)", (NpgsqlConnection) Connection);
cursCmd.Transaction = tr;
NpgsqlParameter rf = new NpgsqlParameter("ref", NpgsqlTypes.NpgsqlDbType.Refcursor);
rf.Direction = ParameterDirection.InputOutput;
cursCmd.Parameters.Add(rf);
我必须添加这个来使用
NpgsqlDataReader-myReader正确:

tr.Commit();

当我在sql命令之后编写
fetch
时,它可以工作,但不适用。

首先,这里是一些有用的文档:

在本文档中,您可以找到一个
NpgsqlDataAdapter
。此对象还有一个
Fill()
方法(继承自
DbDataAdapter
)。此方法可以使用
数据集
和光标。它将用光标返回的数据填充
数据集


你实际上不能给这个方法一个
DataReader
,但是你可以给一个
DataTable
,我想你可以用它做点什么。

我对我的问题有一些答案

问题:我有一个存储的PLSQL过程,它返回
refCursor
。我必须使用
DataReader
获取返回的数据,但是当我添加参数时,db返回了

要遍历所有返回的数据,我必须这样编写代码:

NpgsqlTransaction tr = (NpgsqlTransaction) Connection.BeginTransaction();
NpgsqlCommand cursCmd = new NpgsqlCommand("someStoredProcedure", (NpgsqlConnection) Connection);
cursCmd.Transaction = tr;
NpgsqlParameter rf = new NpgsqlParameter("ref", NpgsqlTypes.NpgsqlDbType.Refcursor);
rf.Direction = ParameterDirection.InputOutput;
cursCmd.Parameters.Add(rf);

NpgsqlParameter param2 = new NpgsqlParameter("param1", NpgsqlTypes.Int32);
rf.Direction = ParameterDirection.Input;
cursCmd.Parameters.Add(param2);
NpgsqlDataReader r = cmd.ExecuteReader();

while (r.Read())
{
    ; // r.GetValue(0);
}
r.NextResult();
while(r.Read())
{
    ;
}

tr.Commit();
请注意,您不会像
func(:param1)
那样在sql中编写参数

如果函数中有参数,请仅将函数名指定给
CommandText
属性,并像往常一样将参数添加到
NpgsqlCommand.parameters
集合中。Npgsql将负责正确绑定您的参数

但现在我有另一个问题。当我将另一个输出参数传递给我的
CommandText
时,结果中有两个字段。其中一个是
0{my first output param}
,另一个是


在Oracle中,我可以直接将
RefCursor
参数转换为
DataReader
,但在postgresql中,我不能。通过在同一事务中使用两个命令,我解决了
Out
参数的问题

在第一个命令中,我读取out参数,然后执行下一个命令

第二个命令如下所示:

var cmd2 = new NpgsqlCommand("FETCH ALL FROM \"list\"", (NpgsqlConnection) Connection)
其中
list
在存储过程中创建的游标的名称。因此,我从数据库中选择了数据。

供您参考:

/// <summary>
/// Get data from the returning refcursor of postgresql function
/// </summary>
/// <param name="FunctionName">Function name of postgresql</param>
/// <param name="Parameters">parameters to pass to the postgresql function</param>
/// <param name="ErrorOccured">out bool parameter to check if it occured error</param>
/// <returns></returns>
public List<DataTable> GetRefCursorData(string FunctionName, List<object> Parameters, out bool ErrorOccured)
{ 
    string connectstring = ""; //your connectstring here
    List<DataTable >  dtRtn =new List<DataTable>();
    NpgsqlConnection connection = null;
    NpgsqlTransaction transaction = null;
    NpgsqlCommand command = null;            
    try
    {
        connection = new NpgsqlConnection(connectstring);
        transaction = connection.BeginTransaction();
        command = new NpgsqlCommand();
        command.Connection = connection;
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = FunctionName;
        command.Transaction = transaction;
        //
        if (Parameters != null)
        {
            foreach (object item in Parameters)
            {
                NpgsqlParameter parameter = new NpgsqlParameter();
                parameter.Direction = ParameterDirection.Input;
                parameter.Value = item;
                command.Parameters.Add(parameter);
            }
        }
        //
        NpgsqlDataReader dr = command.ExecuteReader();
        while (dr.Read())
        {
            DataTable dt = new DataTable();
            command = new NpgsqlCommand("FETCH ALL IN " + "\"" + dr[0].ToString() + "\"", Connection); //use plpgsql fetch command to get data back
            NpgsqlDataAdapter da = new NpgsqlDataAdapter(command);
            da.Fill(dt);
            dtRtn.Add(dt); //all the data will save in the List<DataTable> ,no matter the connection is closed or returned multiple refcursors
        }                
        ErrorOccured = false;
        transaction.Commit();
    }
    catch
    { 
        //error handling ...
        ErrorOccured = true;
        if (transaction != null) transaction.Rollback();
    }
    finally
    {
        if (connection != null) connection.Close();
    }
    return dtRtn;
}
//
///从postgresql函数返回的refcursor获取数据
/// 
///postgresql的函数名
///要传递给postgresql函数的参数
///out bool参数检查是否发生错误
/// 
公共列表GetRefCursorData(字符串函数名,列表参数,发生out bool错误)
{ 
string connectstring=”“;//此处是您的connectstring
List dtRtn=新列表();
NpgsqlConnection=null;
NpgsqlTransaction=null;
NpgsqlCommand=null;
尝试
{
连接=新的NpgsqlConnection(connectstring);
事务=连接。BeginTransaction();
command=新的NpgsqlCommand();
command.Connection=连接;
command.CommandType=CommandType.storedProcess;
command.CommandText=函数名;
command.Transaction=事务;
//
if(参数!=null)
{
foreach(参数中的对象项)
{
NpgsqlParameter=新的NpgsqlParameter();
parameter.Direction=ParameterDirection.Input;
参数值=项目;
command.Parameters.Add(参数);
}
}
//
NpgsqlDataReader dr=command.ExecuteReader();
while(dr.Read())
{
DataTable dt=新的DataTable();
command=new NpgsqlCommand(“在“+”\”“+dr[0].ToString()+“\”“,Connection中提取所有数据”);//使用plpgsql FETCH命令获取数据
NpgsqlDataAdapter da=新的NpgsqlDataAdapter(命令);
da.填充(dt);
dtRtn.Add(dt);//所有数据都将保存在列表中,无论连接是否关闭或返回多个引用游标
}                
ErrorOccursed=false;
Commit();
}
抓住
{ 
//错误处理。。。
ErrorOccursed=true;
if(transaction!=null)transaction.Rollback();
}
最后
{
if(connection!=null)connection.Close();
}
返回dtRtn;
}

我认为这是一个相当具体的问题。当您提供函数的示例调用时,这个答案会更有用。例如,我们应该如何初始化列表参数?这一行执行da.Fill(dt)时出现错误“一个命令已经在执行中”;