Как вернуть RefCursor из функции Oracle? - PullRequest
9 голосов
/ 08 ноября 2010

Я пытаюсь выполнить пользовательскую функцию Oracle, которая возвращает RefCursor, используя 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) и вернуть 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, но я резервируюкак последнее средство, но вместо этого я использую хранимые процедуры.

Любая помощь очень ценится!

1 Ответ

15 голосов
/ 08 ноября 2010

Я думаю, что вам не хватает sqlCom.ExecuteNonQuery ();

также вместо запуска select func_test (7) из dual; позволяет переключить егодля запуска функции и передачи параметра

  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 / функции, вы можете обойти это, используя анонимные блоки в вашем коде, я исправил (еще раз не проверял!) Кодвыше, чтобы отразить эту технику.Вот хороший блог (от Марка Уильямса), показывающий эту технику.http://oradim.blogspot.com/2007/04/odpnet-tip-anonymous-plsql-and.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...