我正在尝试执行用户定义的Oracle函数,该函数使用ODP.NET返回RefCursor。这是功能:
CREATE OR REPLACE FUNCTION PKG.FUNC_TEST (ID IN TABLE.ID%type)
RETURN SYS_REFCURSOR
AS
REF_TEST SYS_REFCURSOR;
BEGIN
OPEN REF_TEST FOR
SELECT *
FROM TABLE;
RETURN REF_TEST;
END;
/
我可以在Toad中调用此函数(从dual中选择func_test(7))并返回CURSOR。但是我需要使用C#和ODP.NET来获取光标以填充DataSet,但我不断得到NullReferenceException - “对象引用未设置为对象的实例”。以下是我的意见:
OracleConnection oracleCon = new OracleConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
OracleCommand sqlCom = new OracleCommand("select func_test(7) from dual", oracleCon);
sqlCom.Parameters.Add("REF_TEST", OracleDbType.RefCursor, ParameterDirection.ReturnValue);
OracleDataAdapter dataAdapter = new OracleDataAdapter();
dataAdapter.SelectCommand = sqlCom;
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet); //FAILS HERE with NullReferenceException
我能够在使用存储过程和ODP.NET时找到大量信息和示例,但不是从函数返回RefCursors。
编辑:我不想将输入参数显式添加到OracleCommand对象(即sqlCom.Parameters.Add("id", OracleDbType.Int32,ParameterDirection.Input).Value = 7;
),因为这使得很难将其作为通用RESTful Web服务实现,但我保留它作为我的最后手段,但会使用存储过程。
非常感谢任何帮助!
答案 0 :(得分:15)
我认为你错过了 sqlCom.ExecuteNonQuery();
另外,不是运行从双重选择func_test(7); 让我们切换它来运行该函数并传入参数
OracleConnection oracleCon = new OracleConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
// Set the command
string anonymous_block = "begin " +
" :refcursor1 := func_test(7) ;" +
"end;";
//fill in your function and variables via the above example
OracleCommand sqlCom= con.CreateCommand();
sqlCom.CommandText = anonymous_block;
// Bind
sqlCom.Parameters.Add("refcursor1", OracleDbType.RefCursor);
sqlCom.Parameters[0].Direction = ParameterDirection.ReturnValue;
try
{
// Execute command; Have the parameters populated
sqlCom.ExecuteNonQuery();
// Create the OracleDataAdapter
OracleDataAdapter da = new OracleDataAdapter(sqlCom);
// Populate a DataSet with refcursor1.
DataSet ds = new DataSet();
da.Fill(ds, "refcursor1", (OracleRefCursor)(sqlCom.Parameters["refcursor1"].Value));
// Print out the field count the REF Cursor
Console.WriteLine("Field count: " + ds.Tables["refcursor1"].Columns.Count);
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
finally
{
// Dispose OracleCommand object
cmd.Dispose();
// Close and Dispose OracleConnection object
con.Close();
con.Dispose();}
这是基于可以找到的示例ODP @%ora_home%\ Client_1 \ ODP.NET \ samples \ RefCursor \ Sample5.csproj
如果您想避免(为了更好或更差!)每个proc / function调用的自定义构建的param集合,您可以通过在代码中使用匿名块来解决这个问题,我已经修改了(再次未经测试!)代码以上反映了这种技术。 这是一个很好的博客(来自马克威廉姆斯),展示了这种技术。 http://oradim.blogspot.com/2007/04/odpnet-tip-anonymous-plsql-and.html