简体   繁体   English

从Oracle.DataAccess.dll抛出NullReferenceException

[英]NullReferenceException Thrown from Oracle.DataAccess.dll

I am having a problem using Oracle Data Provider with .NET . 我在将Oracle Data Provider与.NET结合使用时遇到问题。 I am using an array of a User-Defined Objects as an IN parameter to a stored procedure. 我正在使用用户定义对象的数组作为存储过程的IN参数。 I have added the database schema to Visual Studio 2015 Server Explorer and generated the Custom Type Class corresponding to the UDT I am using. 我已将数据库架构添加到Visual Studio 2015服务器资源管理器,并生成了与我正在使用的UDT相对应的自定义类型类。 I am using the following code to call the procedure. 我正在使用以下代码来调用该过程。

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

The problem is it throws a NullReferenceException from within the Oracle Driver, Specifically from Oracle.DataAccess.Types.OracleUdt.SetValue(OracleConnection con, IntPtr pUdt, Int32 attrIndex, Object value, Object statusArray) . 问题是它从Oracle驱动程序(特别是从Oracle.DataAccess.Types.OracleUdt.SetValue(OracleConnection con, IntPtr pUdt, Int32 attrIndex, Object value, Object statusArray)引发NullReferenceException

Notes: 笔记:

  • The connection is tested with other procedure calls and it is working properly. 该连接已通过其他过程调用进行了测试,并且工作正常。
  • I have made sure through the debugger that the array elements are not null and their " IsNull " property is set to false, and that their members are not null and each members " IsNull " property is set to false. 我已通过调试器确保数组元素不为null且其“ IsNull ”属性设置为false,并且其成员也不为null且每个成员的“ IsNull ”属性设置为false。
  • The UDT is defined as follows: UDT的定义如下:

      CREATE OR REPLACE TYPE my_type AS OBJECT ( id NUMBER; value NUMBER; ) 
  • The procedure takes a custom collection type defined as follows: 该过程采用如下定义的自定义收集类型:

     CREATE OR REPLACE my_type_varray AS VARRAY(50) OF my_type 
  • The parameter's settings are the only accepted settings, I have tried creating a custom type for a collection but it generates an error saying "wrong number or types of arguments in call to MYPROCEDURE", these setting generate the NullReferenceException, which means it accepted the parameters and moved on to process them. 参数的设置是唯一可接受的设置,我尝试为集合创建自定义类型,但是它会生成一个错误消息,提示“对MYPROCEDURE的调用中参数的数量或类型错误”,这些设置会生成NullReferenceException,这意味着它接受了参数然后继续进行处理。

  • For sake of simplicity I have omitted a lot of the code, and I have written it manually. 为了简单起见,我省略了很多代码,并且手动编写了代码。 But I will post it if I had to. 但是如果需要,我会发布它。

Additional info: 附加信息:
stacktrace: 堆栈跟踪:

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()

I have created a simple test procedure called TEST , which takes a single instance of the UDT. 我创建了一个简单的测试过程TEST ,它使用UDT的单个实例。 The procedure is defined as follows: 该过程定义如下:

FUNCTION test(obj in MY_TYPE) RETURN NUMBER IS
BEGIN
  RETURN obj.id*obj.value;
END;

The code for calling the procedure is : 调用该过程的代码是:

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

The previous code worked properly and the result was 6. 先前的代码正常工作,结果为6。

As far as I know you cannot use VARRAY as parameter. 据我所知,您不能使用VARRAY作为参数。 The only supported collection type are Associative Arrays (Index-By Tables), eg 唯一受支持的集合类型是关联数组(按表索引),例如

TYPE TArrayOfNumber IS TABLE OF NUMBER INDEX BY INTEGER;

So, you would have to pass two parameters, one array of id and one array for value . 因此,您必须传递两个参数,一个id数组和一个value数组。 Then you can create the OBJECT type within PL/SQL 然后您可以在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;

and in C# like this: 在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:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM