Проблема с использованием Dapper с C# для вызова хранимой процедуры Oracle с refcursor в качестве выходного параметра, однако refcursor в качестве возвращаемого значения работает

Учитывая этот хранимый оракулом пакет процедур:

CREATE OR REPLACE 
PACKAGE TESTPKG AS 
  FUNCTION TestReturnRefCursor RETURN SYS_REFCURSOR;
  PROCEDURE TestingRefCursorsAsOutParam (outp OUT SYS_REFCURSOR);
END TESTPKG

И это тело пакета:

CREATE OR REPLACE
PACKAGE BODY TESTPKG AS

  FUNCTION TestReturnRefCursor RETURN SYS_REFCURSOR AS
    outp SYS_REFCURSOR;
  BEGIN
    OPEN outp FOR SELECT * FROM TABLENAME;
    RETURN outp; 
  END TestReturnRefCursor;

  PROCEDURE TestingRefCursorsAsOutParam (outp OUT SYS_REFCURSOR) AS 
  BEGIN
    OPEN outp FOR SELECT * FROM TABLENAME;
  END TestingRefCursorsAsOutParam;

END TESTPKG;

Я пытаюсь использовать Dapper для вызова любой функции. Я создал класс OracleDynamicParameters, реализующий Dapper.SqlMapper.IDynamicParameters, который я нашел в этом сообщении после поиска в StackOverflow: https://gist.github.com/vijaysg/3096151

Вызов хранимой функции TestReturnRefCursor отлично работает с этим кодом:

        var conn = new OracleConnection(ConfigurationManager.ConnectionStrings["DataConnection"].ConnectionString);
        conn.Open();
        var p = new OracleDynamicParameters();
        p.Add("retSet", dbType: OracleDbType.RefCursor, direction: ParameterDirection.ReturnValue);
        conn.Execute("TESTPKG.TestReturnRefCursor ", param: p, commandType: CommandType.StoredProcedure);
        var refcur = p.Get<OracleRefCursor>("retSet");
        // do something with refcur
        conn.Close();

Однако, когда я пытаюсь вызвать хранимую процедуру TestingRefCursorsAsOutParam с помощью этого кода:

var conn = new OracleConnection(ConfigurationManager.ConnectionStrings["DataConnection"].ConnectionString);
conn.Open();
var p = new OracleDynamicParameters();
p.Add("retSet", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);
conn.Execute("TESTPKG.TestingRefCursorsAsOutParam ", param: p, commandType: CommandType.StoredProcedure);
var refcur = p.Get<OracleRefCursor>("retSet");
// do something with refcur
conn.Close();

Я получаю исключение OracleException из Oracle.ManagedDataAccess.dll с подробностями:

"ORA-06550: line 1, column 7:\nPLS-00306: wrong number or types of arguments in call to 'TESTINGREFCURSORSASOUTPARAM'\nORA-06550: line 1, column 7:\nPL/SQL: Statement ignored"

Я обнаружил после поиска другого поста stackoverflow, где иногда параметры не привязаны, если они равны нулю, если вы специально не установили их значение как DBNull.Value, поэтому я попытался изменить строку добавления параметра на:

p.Add("retSet", value: DBNull.Value, dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);

но это не помогло.

Я могу просто вызвать эту хранимую процедуру, используя обычный код оракула С#:

var cmd = conn.CreateCommand();
cmd.CommandText = "TESTPKG.TestingRefCursorsAsOutParam";
cmd.CommandType = CommandType.StoredProcedure;

var outparam = new OracleParameter();
outparam.ParameterName = "retSet";
outparam.Direction = ParameterDirection.Output;
outparam.OracleDbType = OracleDbType.RefCursor;

cmd.Parameters.Add(outparam);

OracleDataAdapter da = new OracleDataAdapter(cmd);
cmd.ExecuteNonQuery();

var refcur = (OracleRefCursor)cmd.Parameters[0].Value;

Я что-то упускаю или Dapper работает неправильно?


person J.T. Dorion    schedule 08.12.2015    source источник
comment
У меня нет оракула для проверки, но я подозреваю, что проблема в том, что ваш набор параметров не реализует IParameterCallbacks для проверки обновленных значений параметров. Есть ли какая-то причина, по которой вы не можете просто использовать предварительно свернутый класс DynamicParameters?   -  person Marc Gravell    schedule 09.12.2015
comment
Спасибо за ответ, Марк! Когда я начал использовать Dapper для вызова функции/процедуры, использующей refcursor, я не нашел Dbtype.Refcursor в списке параметров. Затем я сделал быстрый поиск в стеке и нашел это: dapper с хранимыми процедурами оракула, которые возвращают курсоры"> stackoverflow.com/questions/7390015/ Что привело меня к мысли, что требуется класс OracleDynamicParameters. Я использую сильную (1.4) версию Dapper по умолчанию, которую вы получаете с помощью NuGet.   -  person J.T. Dorion    schedule 09.12.2015
comment
Если я изменю OracleDynamicParameters на DynamicParameters и добавлю к этому вызов параметра (опуская объявление dbtype): codep.Add(retSet, direction: ParameterDirection.Output);code Я все еще получаю то же самое сообщение об ошибке, что и выше - неправильный номер или типы аргументов.   -  person J.T. Dorion    schedule 09.12.2015
comment
Мне очень сложно отлаживать это, так как у меня нет Oracle; но ключевое здесь — строка 171 по существу; это выполнено? Это метод AddParameters, который изменяется при добавлении параметров.   -  person Marc Gravell    schedule 09.12.2015
comment
Кстати; вероятно, есть более чистый способ реализовать это, написав обработчик типа для OracleRefCursor - немного похоже на это, но проще (в этом коде есть два разных представления — SqlGeography, которое использует поставщик БД, и DbGeography, которое использует EF; все, что вам действительно нужно настроить, это OracleDbType)   -  person Marc Gravell    schedule 09.12.2015
comment
Я просмотрел источник для динамических параметров и реализовал как IParameterCallbacks, так и IParameterLookup, по существу скопировав и вставив туда код. Я также попытался создать обработчик типов для OracleRefCursor. Я просмотрел тесты, чтобы выяснить, как это сделать, и зарегистрировал обработчик типов, но я думаю, что часть проблемы может заключаться в том, что вы не можете самостоятельно создать экземпляр OracleRefCursor, чтобы прикрепить его к параметру — он создается OracleCommand.   -  person J.T. Dorion    schedule 18.12.2015


Ответы (1)


Если вы не хотите использовать строгий тип для своего результата с помощью dapper (например, Query<YourStrongType> ), вы можете использовать Query<dynamic>, приведенный ниже код должен работать:

 IEnumerable<dynamic> results = null;
 using (var conn = new OracleConnection(ConfigurationManager.ConnectionStrings["DataConnection"].ConnectionString))
{
    var p = new OracleDynamicParameters();
    p.Add("outp ", dbType: OracleDbType.RefCursor, direction: ParameterDirection.Output);
    results = conn.Query<dynamic>("TESTPKG.TestingRefCursorsAsOutParam", p, commandType: CommandType.StoredProcedure);

    foreach (var row in results)
    {
         var fields = row as IDictionary<string, object>;
    }
}
person omaraguirre    schedule 15.12.2015