我在将 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();
问题是它从 Oracle 驱动程序中抛出一个 NullReferenceException
,特别是从 Oracle.DataAccess.Types.OracleUdt.SetValue(OracleConnection con, IntPtr pUdt, Int32 attrIndex, Object value,对象状态数组)
。
注意事项:
- 连接已通过其他过程调用进行测试,并且工作正常。
- 我已通过调试器确保数组元素不为空且它们的“
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。
最佳答案
据我所知,您不能使用 VARRAY
作为参数。唯一支持的集合类型是关联数组(索引表),例如
TYPE TArrayOfNumber IS TABLE OF NUMBER INDEX BY INTEGER;
因此,您必须传递两个参数,一个是id
数组,另一个是value
数组。然后你可以在 PL/SQL 中创建 OBJECT 类型
PROCEDURE MYPROCEDURE(IdList IN TArrayOfNumber, ValueList IN TArrayOfNumber ) IS
my_type_list my_type_varray;
BEGIN
FOR i IN IdList.FIRST..IdList.LAST LOOP
my_type_list(i) := my_type(IdList(i), ValueList(i));
END LOOP;
...
END;
在 C# 中是这样的:
var par1 = cmd.Parameters.Add("IdList ", OracleDbType.Int16, ParameterDirection.Input);
par1.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
par1.Value = new int[] { 1, 2};
par1.Size = 2:
var par2 = cmd.Parameters.Add("ValueList ", OracleDbType.Int16, ParameterDirection.Input);
par2.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
par2.Value = new int[] { 3, 4};
par2.Size = 2:
关于c# - Oracle.DataAccess.dll 抛出 NullReferenceException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53185101/