Выполнить функцию оракула, которая возвращает ссылочный курсор в C # - PullRequest
10 голосов
/ 21 августа 2010

У меня есть пакет оракула с процедурой, в которой есть исходящий курсор. Насколько я понимаю, это довольно стандартно.

Что мне не понравилось, так это то, что мне пришлось написать тонну кода, чтобы просто увидеть результат. Итак, я задал этот вопрос , и оказалось, что я могу получить то, что хочу, создав функцию, которая оборачивает процедуру.

Обновление: Похоже, мне больше не нужна эта функция, но, возможно, в любом случае стоит узнать, кому интересно узнать оригинальный вопрос и ответить на обновления.

Вот функция

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'); 

Использование варианта Абхи для текста команды

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

привело к

Инструкция на "0x61c4aca5" ссылка на память в "0x00000ce1". память не может быть «прочитана».

Я просто лаю не на том дереве?

Обновление Попытка добавить выходной параметр не помогает.

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

Не уверен, какое имя должно быть , поскольку оно является возвращаемым значением функции (я пробовал пустую пустую строку, mypackage.getquestionsForPrint), но во всех случаях это просто результаты в

ORA-06550: строка 1, столбец 7: PLS-00306: неправильный номер или типы аргументы в призыве 'GetquestionsForPrint'

Окончательное редактирование (надеюсь)

Очевидно, Гадди задал аналогичный вопрос через 3 месяца после того, как я это сделал. Он получил ответ на вопрос

  • Установить текст команды в анонимный блок
  • Привязать параметр к курсору ссылки, устанавливая направление вывода
  • Call Execute без читателя.
  • Тогда используйте ваш параметр

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 ]

5 голосов
/ 19 февраля 2011

Я не проверял это с помощью функции, но для моих хранимых процедур.Я указываю параметр out для refCursor.

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

Если вы можете заставить функцию работать с CommandType.Text.Интересно, можете ли вы попробовать добавить параметр выше, кроме как в следующем направлении:

ParameterDirection.ReturnValue

Я использую Oracle.DataAccess версии 2.111.6.0

1 голос
/ 11 февраля 2019

Мне приходилось переходить от вопроса к ответу, чтобы выяснить полный код, который работает. Поэтому я даю полный код, который работал для меня на других -

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);
         }
     }
 }

Надеюсь, это поможет.

0 голосов
/ 28 апреля 2013

Я знаю, что это довольно старый пост, но, так как мне потребовалось много времени, чтобы выяснить все мелочи, связанные с получением .NET, чтобы "хорошо сражаться" с Oracle, я подумал, что выложу этот совет для кто-нибудь еще в этой неприятной ситуации.

Я часто вызываю хранимые процедуры Oracle, которые возвращают REF_CURSOR в нашей среде (.NET 3.5 для Oracle 11g). Для функции вы действительно можете назвать параметр как угодно, но тогда вам нужно установить его System.Data.ParameterDirection = ParameterDirection.ReturnValue, затем ExecuteNonQuery против объекта OracleCommand. В этот момент значением этого параметра будет ref_cursor, который вернула функция Oracle. Просто приведите значение как OracleDataReader и выполните цикл по OracleDataReader.

Я бы опубликовал полный код, но я написал уровень доступа к данным в VB.NET несколько лет назад, и основная часть кода, потребляющего уровень доступа к данным (наша корпоративная интрасеть), находится на C #. Я полагал, что смешивание языков в одном ответе было бы большим ошибком.

0 голосов
/ 21 августа 2010

Я предполагаю, что вы не можете вызвать функцию с объектом Command типа StoredProcedure. Можете ли вы попробовать объект Command типа «Текст» и выполнить функцию в тексте команды?

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