在 ODP.NET 中将 raw(32) 参数数组传递给 Oracle 存储过程

本文关键字:数组 存储过程 Oracle 参数 NET ODP 中将 raw | 更新日期: 2023-09-27 18:30:40

我有一个自定义类型和存储过程,定义如下:

CREATE OR REPLACE TYPE GuidArray is varray(1000) of RAW(32);
/
CREATE OR REPLACE 
PROCEDURE BulkInsertTempItemGuid
(
  ItemGuidList IN GuidArray default null
) AS
BEGIN
  --
  -- procedure body here
  --
END;
/

我正在尝试从 c# 应用程序在 Oracle 的 ODP .NET 中调用此存储过程。我似乎无法正确设置我的OracleParameter,因为 Oracle 告诉我我没有向它发送正确的参数集。我正在设置集合类型,OracleDbType和值,如下所示。 parametersOracleParameterarrangedGuidListIEnumerable<Guid>

parameter.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
parameter.OracleDbType = OracleDbType.Raw;
parameter.Value = arrangedGuidList.ToArray();

例外:

ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'BulkInsertTempItemGuid'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

在 ODP.NET 中将 raw(32) 参数数组传递给 Oracle 存储过程

使用数组调用存储过程一次(而不是调用接受原子项的过程并多次调用它)时,必须将 OracleDbType 设置为数组。该值设置为在自定义 oracle 数据类型类中指定的基础结构化数据。在本例中,它是一个字节 [][]。

parameter.OracleDbType = OracleDbType.Array;
parameter.UdtTypeName = "GUIDARRAY";
parameter.Value = arrangedGuidList.ToArray();
// Note, do NOT set the collection type. Default it to "none"

然后,我定义了我的 Oracle 自定义类型。有关示例,请参阅此处。我改编了 SimpleVarray/SimpleVarrayFactory 类,但让它们与 Byte[][] 一起工作。

%ODAC_HOME%'ODACsamples'odp.net'4'UDT

工厂类的关键部分是自定义类型映射必须与参数的 UdtTypeName 属性匹配,并且全部大写。似乎 OracleCustomTypeMapping 导致 ODAC 在运行时将中指定的自定义类型绑定到参数中,并通过 ToCustomObject/FromCustomObject 方法在后台的某个地方构建 GuidArray 类。

[OracleCustomTypeMapping("GUIDARRAY")]
public class GuidArrayFactory : IOracleCustomTypeFactory, IOracleArrayTypeFactory
{
    public IOracleCustomType CreateObject()
    {
        return new GuidArray();
    }
    // IOracleArrayTypeFactory Inteface
    public Array CreateArray(int numElems)
    {
        return new Byte[numElems][];
    }
    public Array CreateStatusArray(int numElems)
    {
        // CreateStatusArray may return null if null status information 
        // is not required.
        return new OracleUdtStatus[numElems];
    }
}

-

    // See %ODAC_HOME%'ODACsamples'odp.net'4'UDT
    public class GuidArray : IOracleCustomType, INullable
    {
        [OracleArrayMapping]
        public Byte[][] Array;
        private OracleUdtStatus[] m_statusArray;
        public OracleUdtStatus[] StatusArray
        {
            get
            {
                return m_statusArray;
            }
            set
            {
                m_statusArray = value;
            }
        }
        private bool m_bIsNull;
        public bool IsNull
        {
            get
            {
                return m_bIsNull;
            }
        }
        public static GuidArray Null
        {
            get
            {
                GuidArray obj = new GuidArray();
                obj.m_bIsNull = true;
                return obj;
            }
        }
        public void ToCustomObject(OracleConnection con, IntPtr pUdt)
        {
            object objectStatusArray = null;
            Array = (Byte[][])OracleUdt.GetValue(con, pUdt, 0, out objectStatusArray);
            m_statusArray = (OracleUdtStatus[])objectStatusArray;
        }
        public void FromCustomObject(OracleConnection con, IntPtr pUdt)
        {
            OracleUdt.SetValue(con, pUdt, 0, Array, m_statusArray);
        }
        public override string ToString()
        {
            if (m_bIsNull)
                return "GuidArray.Null";
            string rtnstr = String.Empty;
            if (m_statusArray[0] == OracleUdtStatus.Null)
                rtnstr = "NULL";
            else
                rtnstr = Array.GetValue(0).ToString();
            for (int i = 1; i < m_statusArray.Length; i++)
            {
                if (m_statusArray[i] == OracleUdtStatus.Null)
                    rtnstr += "," + "NULL";
                else
                    rtnstr += "," + Array.GetValue(i);
            }
            return "GuidArray(" + rtnstr + ")";
        }
    }