Как вернуть Рефкурсор из функции Oracle?
Я пытаюсь выполнить пользовательскую функцию Oracle, которая возвращает Рефкурсор, используя ODP.NET - ... Вот функция:
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 (выберите func_test (7) из dual) и вернуть курсор. Но мне нужно получить курсор с помощью C# и ODP.NET чтобы заполнить набор данных, но я продолжаю получать исключение 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 от функции.
EDIT: Я не хочу явно добавлять входные параметры в объект OracleCommand (т. е. sqlCom.Parameters.Add("id", OracleDbType.Int32,ParameterDirection.Input).Value = 7;
), поскольку это затрудняет реализацию этого как общего веб-сервиса RESTful, но я резервирую его в качестве последнего средства, но вместо этого буду использовать хранимые процедуры.
любая помощь очень ценится!
1 ответов
Я думаю, что вы пропускаете sqlCom.ExecuteNonQuery ();
кроме того, вместо выберите func_test (7) из dual; позволяет переключить его для запуска функции и передать в param
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
Если вы хотите избежать (к лучшему или худшему!) пользовательская коллекция param для каждого вызова proc / function можно обойти это, используя анонимные блоки в вашем коде, я ammended (еще раз непроверенный!) код выше, чтобы отразить эту технику. Вот хороший блог (не кто иной, как Марк Уильямс), показывающий эту технику. http://oradim.blogspot.com/2007/04/odpnet-tip-anonymous-plsql-and.html