【发布时间】:2011-04-01 21:56:13
【问题描述】:
我有一个 oracle 包,其中包含一个包含 in 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,结果相同。
EDIT 接受 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();
}
【问题讨论】:
-
没有“racleCommand”之类的东西,发布真实代码。
-
抱歉在副本中遗漏了一些内容
-
康拉德,你不需要包装器 - 我更新了之前的问题。不懂C#所以不能评论那部分。就个人而言 - 我相信很多人会在这个问题上拒绝我 - 我通常会说一个程序应该做一些工作并且可以对传入和未传入的数据产生影响(你不'不一定知道),并且函数应该根据传入的数据返回结果,并且最好没有任何副作用。但它是最适合你正在做的事情的。回过头来修改旧代码不太可能增加太多,我想。
-
我也遇到过类似的困难。所以我不得不求助于将我的函数更改为存储过程。我没有回答,因为这个问题很老了。如果您的函数返回 REFCURSOR,则更改 Slider345 给出的 CommandType 建议不起作用。如果你有一个标量函数,它会工作,它返回一个值而不是一个记录集。在这种情况下,您也必须在“SELECT function_name FROM DUAL”之类的查询中使用您的函数。也许您可以在上述功能上尝试这种方法。将您的命令类型更改为 TEXT,然后更改语法以调用该函数。
-
您是否看到this link 上的“在 C# 中测试 REF CURSOR 过程”部分 - 对我来说是页面的一半。