Передача массива необработанных (32) аргументов в хранимую процедуру Oracle в ODP.NET

У меня есть пользовательский тип и хранимая процедура, определенные следующим образом:

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;
/

Я пытаюсь вызвать эту хранимую процедуру в Oracle ODP .NET из приложения С#. Кажется, мне не удается правильно настроить OracleParameter, поскольку Oracle говорит мне, что я не отправляю ему правильный набор параметров. Я устанавливаю CollectionType, OracleDbType и Value следующим образом. parameters — это OracleParameter, а arrangedGuidList — это IEnumerable<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

person Stealth Rabbi    schedule 09.09.2013    source источник
comment
Я видел несколько ссылок на размещение типов и процедур в пакете. Я пробовал это и все еще получаю те же результаты. Я также пробовал более простую процедуру и использовал ассоциативный массив списка int, а не varray, например. ТИП IntList - ТАБЛИЦА ЧИСЛОВ (10,0); oracle.com/technetwork/issue-archive/ 2007/07-январь/   -  person Stealth Rabbi    schedule 11.09.2013


Ответы (1)


При однократном вызове хранимой процедуры с массивом (вместо многократного вызова процедуры, которая принимает атомарные элементы), вы должны задать для OracleDbType значение Array. Значение устанавливается в соответствии со структурой базовых данных, как указано в пользовательском классе типа данных оракула. В данном случае это byte[][].

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 во время выполнения привязывать пользовательский тип, указанный в параметре, и создавать класс GuidArray где-то под капотом с помощью методов ToCustomObject/FromCustomObject.

[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 + ")";

        }
    }
person Stealth Rabbi    schedule 12.09.2013