С# Oracle Сохраненная процедура Параметр Заказ

С помощью этого

PROCEDURE "ADD_BOOKMARK_GROUP" (
  "NAME" IN VARCHAR2, 
  "BOOKMARK_GROUP_ID" IN NUMBER, 
  "STAFF_ID" IN VARCHAR2,
  "MAX_NO" IN INT,
  "NUMFOUND" OUT INT, 
  "NEW_ID" OUT NUMBER) IS

BEGIN

NEW_ID := -1;

SELECT COUNT(*) INTO NUMFOUND FROM BOOKMARK_GROUP_TABLE WHERE STAFF_ID = STAFF_ID;

IF NUMFOUND < MAX_NO THEN
    INSERT INTO BOOKMARK_GROUP_TABLE (NAME, BOOKMARK_GROUP_ID, STAFF_ID) VALUES(NAME, BOOKMARK_GROUP_ID, STAFF_ID);
    SELECT BGT_SEQUENCE.currval INTO NEW_ID FROM dual;
END IF;
END;

Мне интересно, что если я не добавлю параметры в том порядке, в котором они были определены, например,

OracleCommand cmd = new OracleCommand("ADD_BOOKMARK_GROUP", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("NAME", name));
...
cmd.Parameters.Add(new OracleParameter("NEW_ID", OracleDbType.Decimal)).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new OracleParameter("NUMFOUND", OracleDbType.Int32)).Direction = ParameterDirection.Output;

вместо

OracleCommand cmd = new OracleCommand("ADD_BOOKMARK_GROUP", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("NAME", name));
...
cmd.Parameters.Add(new OracleParameter("NUMFOUND", OracleDbType.Int32)).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new OracleParameter("NEW_ID", OracleDbType.Decimal)).Direction = ParameterDirection.Output;

Значения, возвращаемые

cmd.Parameters["NEW_ID"].Value.ToString()

и

cmd.Parameters["NUMFOUND"].Value.ToString()

получить swapped, хотя запуск процедуры через VS2008 Server Explorer возвращает правильные данные.

Почему это?

Ответ 1

Я не бафф Oracle, поэтому я не могу проверить - но похоже, что они передаются по положению (а не по имени). Нравственный эквивалент:

EXEC SomeProc 'Foo', 'Bar'

вместо:

EXEC SomeProc @arg1='Foo', @arg2='Bar'

Это не очень редко - в течение многих лет (в COM-дни) много моего кода приходилось работать с драйвером ADODB с положением.

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

cmd.Parameters.Add(new    OracleParameter("BANANA", ...
cmd.Parameters.Add(new    OracleParameter("GUITAR", ...
...
cmd.Parameters["BANANA"].Value.ToString()
cmd.Parameters["GUITAR"].Value.ToString()

Если приведенное выше действие выполняется без ошибок, оно проходит по положению. И он передается положением... затем просто добавляет их в правильном порядке; -p И никогда не добавляйте новые параметры, кроме как в конце...

Ответ 2

Возможно, вы можете установить параметр BindByName в объекте OracleCommand. Это работает для прямых SQL-запросов с параметрами, я не пробовал его с хранимыми процедурами, но это было бы логично...

cmd.BindByName = true;

Ответ 3

Не ответ на вопрос, но вы можете использовать "insert... return... in" вместо select bgt_sequence.currval из двойного, например:

begin
  insert into test (id)
  values(test_seq.nextval)
  returning id into p_id;
end;

См. http://www.adp-gmbh.ch/ora/sql/insert_into_x_returning_y.html