У меня проблема с использованием Oracle Data Provider с .NET. Я использую массив пользовательских объектов в качестве параметра IN для хранимой процедуры. Я добавил схему базы данных в обозреватель серверов Visual Studio 2015 и сгенерировал пользовательский класс типов, соответствующий UDT, который я использую. Я использую следующий код для вызова процедуры.
OracleCommand cmd = DataBase.Connection.CreateCommand();
cmd.CommandText = "MYPROCEDURE";
cmd.CommandType = CommandType.StoredProcedure;
cmd.BindByName = true;
MY_TYPE[] arr = new MY_TYPE[2];
arr[0] = new MY_TYPE(1, 2);
arr[1] = new MY_TYPE(3, 4);
OracleParameter pEntries = new OracleParameter();
pEntries.ParameterName = "ENTRIES";
pEntries.Direction = ParameterDirection.Input;
pEntries.OracleDbType = OracleDbType.Array;
pEntries.UdtTypeName = "MY_TYPE";
pEntries.Value = arr;
pEntries.Size = 2;
cmd.Parameters.Add(pEntries);
cmd.Connection.Open();
cmd.ExecuteNonQuery();
Проблема в том, что он выдает NullReferenceException
из драйвера Oracle, в частности, из Oracle.DataAccess.Types.OracleUdt.SetValue(OracleConnection con, IntPtr pUdt, Int32 attrIndex, Object value, Object statusArray)
.
Заметки:
- Соединение проверено с другими вызовами процедур и работает правильно.
- С помощью отладчика я убедился, что элементы массива не являются нулевыми, а их свойство "
IsNull
" имеет значение false, и что их элементы не являются нулевыми, а свойство каждого члена "IsNull
" имеет значение false. UDT определяется следующим образом:
CREATE OR REPLACE TYPE my_type AS OBJECT ( id NUMBER; value NUMBER; )
Процедура принимает пользовательский тип коллекции, определенный следующим образом:
CREATE OR REPLACE my_type_varray AS VARRAY(50) OF my_type
Настройки параметра являются единственными допустимыми настройками, я попытался создать собственный тип для коллекции, но он выдает ошибку, говорящую «неправильное число или типы аргументов при вызове MYPROCEDURE», эти настройки генерируют исключение NullReferenceException, что означает, что он принял параметры и перешли к их обработке.
Для простоты я опустил большую часть кода и написал его вручную. Но выложу, если надо.
Дополнительная информация:
трассировка стека:
Oracle.DataAccess.Types.OracleUdt.SetValue(OracleConnection con, IntPtr pUdt, Int32 attrIndex, Object value, Object statusArray)
at Oracle.DataAccess.Types.OracleUdt.SetValue(OracleConnection con, IntPtr pUdt, Int32 attrIndex, Object value)
at Oracle.DataAccess.Client.OracleParameter.SetUDTFromArray(OracleConnection conn, Object array, Int32 i)
at Oracle.DataAccess.Client.OracleParameter.PreBind_Collection(OracleConnection conn)
at Oracle.DataAccess.Client.OracleParameter.PreBind(OracleConnection conn, IntPtr errCtx, Int32 arraySize, Boolean bIsFromEF, Boolean bIsSelectStmt) at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()
Я создал простую тестовую процедуру под названием TEST
, которая использует один экземпляр UDT. Процедура определяется следующим образом:
FUNCTION test(obj in MY_TYPE) RETURN NUMBER IS
BEGIN
RETURN obj.id*obj.value;
END;
Код для вызова процедуры:
OracleCommand cmd = DataBase.Connection.CreateCommand();
cmd.CommandText = "TEST";
cmd.CommandType = CommandType.StoredProcedure;
cmd.BindByName = true;
MY_TYPE obj = new MY_TYPE(2, 3);
OracleParameter pEntries = new OracleParameter();
Entries.ParameterName = "obj";
pEntries.Direction = ParameterDirection.Input;
pEntries.OracleDbType = OracleDbType.Object;
pEntries.UdtTypeName = "MY_TYPE";
pEntries.Value = obj;
cmd.Parameters.Add(pEntries);
// -- omitted some code for the return value parameter
cmd.Connection.Open();
cmd.ExecuteNonQuery();
Предыдущий код работал правильно, и результат был 6.
ExecuteNonQuery
или нет. - person Jon Skeet   schedule 07.11.2018