执行一个在C#中返回引用游标的oracle函数

时间:2010-08-20 22:53:20

标签: c# oracle odp.net

我有一个oracle包,其中包含一个带有out参考游标的过程。我的理解是,这是非常标准的。

我不喜欢的是我必须编写大量代码才能看到输出。 So I asked this question事实证明,通过创建一个包装过程的函数,我可以得到我想要的东西。

更新:看起来我不再需要这个功能了但是对于那些好奇的人来说可能值得知道,看看原来的问题和答案更新。

这是函数

FUNCTION GetQuestionsForPrint (user in varchar2)
  RETURN MYPACKAGE.refcur_question
AS  

    OUTPUT MYPACKAGE.refcur_question;

BEGIN 

      MYPACKAGE.GETQUESTIONS(p_OUTPUT => OUTPUT, 
      p_USER=> USER ) ;


  RETURN OUTPUT;
END;

这就是我在SQL Developer中执行它所做的工作

var r refcursor;
exec :r := mypackage.getquestionsForPrint('OMG Ponies');
print r;

所以从现在开始,我可能会将ForPrint功能添加到我的所有程序中。

这让我思考,也许功能是我想要的,我不需要程序。

为了测试这个我尝试从.NET执行该功能,除了我不能这样做。这真的是这样吗。

using (OracleConnection cnn = new OracleConnection("Data Source=Test;User Id=Test;Password=Test;"))
{
    cnn.Open();
    OracleCommand cmd = new OracleCommand("mypackage.getquestionsForPrint");
    cmd.CommandType = System.Data.CommandType.StoredProcedure;

    cmd.Parameters.Add ( "p_USER", "OMG Ponies");

    cmd.Connection = cnn;
    OracleDataReader rdr = cmd.ExecuteReader();

    while (rdr.Read())
    {
        Console.WriteLine(rdr.GetOracleValue(0));
    }

    Console.ReadLine();
}

所以我得到了错误。

getquestionsForPrint is not a procedure or is undefined

我也尝试了ExecuteScalar,结果相同。

编辑采取Slider345的建议我也尝试将命令类型设置为文本并使用以下语句然后我得到  无效的SQL语句

mypackage.getquestionsForPrint('OMG Poinies');

var r refcursor; exec :r :=  mypackage.getquestionsForPrint('OMG Poinies'); 

将Abhi的变体用于命令文本

select mypackage.getquestionsForPrint('OMG Poinies') from dual

导致

  

“0x61c4aca5”的指示   在“0x00000ce1”引用内存。该   记忆无法“读”。

我只是在错误的树上吠叫?

更新 尝试添加输出参数没有帮助。

cmd.Parameters.Add(null, OracleDbType.RefCursor, ParameterDirection.Output);

不确定 名称应该是 ,因为它的函数返回值(我尝试过null,空字符串,mypackage.getquestionsForPrint),但在所有情况下它只是导致

  

ORA-06550:第1行第7栏:   PLS-00306:错误的数量或类型   呼吁中的参数   'getquestionsForPrint'

最终编辑(希望如此)

显然,Guddie在我做了3个月后similar question询问了。他得到了答案

  • 将命令文本设置为匿名块
  • 将参数绑定到参考光标,设置输出方向
  • 呼叫执行非阅读器。
  • 然后使用您的参数

using (OracleConnection cnn = new OracleConnection("Data Source=Test;User Id=Test;Password=Test;"))
{
    cnn.Open();
    OracleCommand cmd = new OracleCommand("mypackage.getquestionsForPrint");
    cmd.CommandType = CommandType.Text;

    cmd.CommandText = "begin " +
              "    :refcursor1 := mypackage.getquestionsForPrint('OMG Ponies') ;"  +
              "end;";

    cmd.Connection = cnn;
    OracleDataAdapter da = new OracleDataAdapter(cmd);
    cmd.ExecuteNonQuery();

    Oracle.DataAccess.Types.OracleRefCursor t = (Oracle.DataAccess.Types.OracleRefCursor)cmd.Parameters[0].Value;
    OracleDataReader rdr = t.GetDataReader();
    while(rdr.Read())
        Console.WriteLine(rdr.GetOracleValue(0));

    Console.ReadLine();
}

4 个答案:

答案 0 :(得分:5)

我没有使用函数测试它,但是我的存储过程。我为refCursor指定了out参数。

command.Parameters.Add(new OracleParameter("refcur_questions", OracleDbType.RefCursor, ParameterDirection.Output));

如果能够使用CommandType.Text的函数。我想知道你是否可以尝试添加上面的参数,除了方向为:

ParameterDirection.ReturnValue

我正在使用Oracle.DataAccess版本2.111.6.0

答案 1 :(得分:1)

我必须在问题和答案之间上下移动才能找出有效的完整代码。因此,我在这里提供了对其他人有用的完整代码-

var sql = @"BEGIN :refcursor1 := mypackage.myfunction(:param1) ; end;";
using(OracleConnection con = new OracleConnection("<connection string>"))
using(OracleCommand com = new OracleCommand())
{
     com.Connection = con;
     con.Open();
     com.Parameters.Add(":refcursor1", OracleDbType.RefCursor, ParameterDirection.Output);
     com.Parameters.Add(":param1", "param");
     com.CommandText = sql;
     com.CommandType = CommandType.Text;
     com.ExecuteNonQuery();
     OracleRefCursor curr = (OracleRefCursor)com.Parameters[0].Value;
     using(OracleDataReader dr = curr.GetDataReader())
     {
         if(dr.Read())
         {
             var value1 = dr.GetString(0);
             var value2 = dr.GetString(1);
         }
     }
 }

希望有帮助。

答案 2 :(得分:0)

我的猜测是你无法使用'StoredProcedure'类型的Command对象调用函数。你能尝试一个'Text'类型的Command对象并在Command Text中执行该函数吗?

答案 3 :(得分:0)

我知道这是一个相当古老的帖子,但是因为我花了这么长时间才弄清楚所有的细节都让.NET与Oracle“好斗”,我想我会把这个建议放在那里处于这种棘手情况的其他任何人。

我经常调用在我们的环境中返回REF_CURSOR的Oracle存储过程(针对Oracle 11g的.NET 3.5)。对于函数,您确实可以将参数命名为您想要的任何内容,但是您需要针对System.Data.ParameterDirection对象设置其ParameterDirection.ReturnValue = ExecuteNonQuery然后OracleCommand。此时,该参数的值将是Oracle函数返回的ref_cursor。只需将值转换为OracleDataReader并循环遍历OracleDataReader

我发布了完整的代码,但是几年前我在VB.NET中编写了数据访问层,而使用数据访问层(我们的企业内部网)的大部分代码都在C#中。我认为在一个响应中混合语言将是更大的失礼。