M.Kamran Asim Ответов: 1

Определенными пользователя Oracle типы данных (UDT) внутри пакета сопоставления .Чистые пользовательские типы


Я сопоставляю пользовательские типы Oracle .Объем пользовательских типов в Oracle доступ к данным Ассамблеи неуправляемым.
Я следил за этой статьей https://www.codeproject.com/Articles/1261430/Calling-Oracles-Stored-Procedures-and-Mapping-User

Я применил простые сценарии.

1. Создан Оракул определяемый пользователем тип на уровне схемы, т. е.

CREATE OR REPLACE  TYPE STUDENT_TYP IS OBJECT (
STUDENT_ID NUMBER,
STUDENT_NAME VARCHAR(20),
ADDRESS VARCHAR(20),
AGE NUMBER,
BIRTH_DATE DATE
);

CREATE OR REPLACE  TYPE STUDENT_TYP_TBL IS TABLE OF STUDENT_TYP;


а вот процедура GET_ALL_STUDENTS body

PROCEDURE GET_ALL_STUDENTS(P_STUDENTS OUT STUDENT_TYP_TBL)
AS
BEGIN

  SELECT *
    BULK COLLECT INTO P_STUDENTS   
    FROM 
    (
    SELECT  STUDENT_TYP(s.student_id,
            s.student_name,
            s.address,
            s.age,
            s.birth_date)
    FROM
    student s) ; 
END;


Приведенный выше пример работает нормально. Выше сценарий просто чтобы объяснить нет никаких проблем в реализации

2. Теперь я определил типы внутри пакета, например:

CREATE OR REPLACE PACKAGE STUDENT_PKG 
AS

TYPE  PHONE_TYP_RC IS RECORD (
PHONE_ID  STUDENT_PHONE.PHONE_ID%TYPE,
PHONE_TYPE STUDENT_PHONE.PHONE_TYPE%TYPE,
PHONE_NUMBER STUDENT_PHONE.PHONE_NUMBER%TYPE
);

TYPE PHONE_RC_TBL IS TABLE OF PHONE_TYP_RC;

PROCEDURE GET_ALL_PHONES(P_PHONES_TBL OUT STUDENT_PKG.PHONE_RC_TBL);

END;


Ниже приводится тело STUDENT_PKG

create or replace PACKAGE BODY STUDENT_PKG 
AS

PROCEDURE GET_ALL_PHONES(P_PHONES_TBL OUT STUDENT_PKG.PHONE_RC_TBL)
IS
BEGIN

SELECT PH.PHONE_ID, PH.PHONE_TYPE, PH.PHONE_NUMBER
 BULK COLLECT INTO P_PHONES_TBL
FROM STUDENT_PHONE PH;

-- END OF GET_ALL_PHONES
END;

--END OF PACKAGE BODY
END;


Когда я добавляю параметр Oracle со всей информацией. Я получил исключение Оракула

"OCI-22303: type \"STUDENT_PKG\".\"PHONE_RC_TBL\" not found"

Я уже определил Пользовательское отображение Oracle с именем STUDENT_PKG.PHONE_RC_TBL
Я уже пробовал со следующими именами

- STUDENT_PKG.PHONE_RC_TBL
- STUDENT_PKG
- PHONE_RC_TBL

Когда я выполняю OracleCommandBuilder.DeriveParameters(command); чтобы получить текстовые параметры команды я получаю следующую информацию

Имя параметра: P_PHONES_TBL
OracleDbType: Массив
OracleDbTypeEx: Массив
UdtTypeName: KAMI.STUDENT_PKG
DbType: Объект


и когда я выполняю, я получаю следующее исключение

OCI-22303: type "KAMI"."STUDENT_PKG" not found

Это означает, что есть что-то сложное для обработки сопоставления udt пакета .Чистый класс.

Вот мое определение .Чистый пользовательский класс для *P_PHONES_TBL* Parmeter

public abstract class CustomTypeBase<T> :
     IOracleCustomType, IOracleCustomTypeFactory, INullable where T : CustomTypeBase<T>, new()
    {
        private bool _isNull;
        public bool IsNull
        {
            get { return this._isNull; }
        }

        public static T Null
        {
            get { return new T { _isNull = true }; }
        }

        public IOracleCustomType CreateObject()
        {
            return new T();
        }

        public abstract void FromCustomObject(OracleConnection con, IntPtr pUdt);
        public abstract void ToCustomObject(OracleConnection con, IntPtr pUdt);
    }

    public abstract class CustomCollectionTypeBase<TType, TValue> : CustomTypeBase<TType>,
                   IOracleArrayTypeFactory where TType : CustomTypeBase<TType>, new()
    {
        [OracleArrayMapping()]
        public TValue[] Values;

        public override void FromCustomObject(OracleConnection connection, IntPtr pointerUdt)
        {
            OracleUdt.SetValue(connection, pointerUdt, 0, Values);
        }

        public override void ToCustomObject(OracleConnection connection, IntPtr pointerUdt)
        {
            Values = (TValue[])OracleUdt.GetValue(connection, pointerUdt, 0);
        }

        public Array CreateArray(int elementCount)
        {
            return new TValue[elementCount];
        }

        public Array CreateStatusArray(int elementCount)
        {
            return new OracleUdtStatus[elementCount];
        }
    }

[OracleCustomTypeMapping("STUDENT_PKG.PHONE_TYP_RC")]
    public class PhoneRecord : CustomTypeBase<PhoneRecord>
    {
        [OracleObjectMapping("PHONE_ID")]
        public int PhoneId { get; set; }

        [OracleObjectMapping("PHONE_TYPE")]
        public string PhoneTYpe { get; set; }

        [OracleObjectMapping("PHONE_NUMBER")]
        public string PhoneNumber { get; set; }

        public override void FromCustomObject(OracleConnection con, IntPtr pUdt)
        {
            OracleUdt.SetValue(con, pUdt, "PHONE_ID", PhoneId);
            OracleUdt.SetValue(con, pUdt, "PHONE_TYPE", PhoneTYpe);
            OracleUdt.SetValue(con, pUdt, "PHONE_NUMBER", PhoneNumber);
        }

        public override void ToCustomObject(OracleConnection con, IntPtr pUdt)
        {
            PhoneId = (int)OracleUdt.GetValue(con, pUdt, "PHONE_ID");
            PhoneTYpe = OracleUdt.GetValue(con, pUdt, "PHONE_TYPE").ToString();
            PhoneNumber = OracleUdt.GetValue(con, pUdt, "PHONE_NUMBER").ToString();
        }
    }

    [OracleCustomTypeMapping("STUDENT_PKG.PHONE_RC_TBL")]
    public class PhoneTable : CustomCollectionTypeBase<PhoneTable, PhoneRecord>
    {

    }


а вот магазинная процедура вызова


OracleCommand command = new OracleCommand("KAMI.STUDENT_PKG.GET_ALL_PHONES", connection);
            command.CommandType = System.Data.CommandType.StoredProcedure;
            try
            {
                //  OracleCommandBuilder.DeriveParameters(command);
                OracleParameter param = new OracleParameter()
                {
                    ParameterName = "P_PHONES_TBL",
                    Direction = System.Data.ParameterDirection.Output,
                    OracleDbType = OracleDbType.Object,
                    OracleDbTypeEx = OracleDbType.Object,
                    UdtTypeName = "STUDENT_PKG.PHONE_RC_TBL",
                };
                command.Parameters.Add(param);

                command.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
            }




Пожалуйста, кто-нибудь испытал то же самое и как решить эту проблему

Что я уже пробовал:

1. я сопоставил UDT уровня схемы с пользовательскими типами, и это сработало для меня
2. Я типы, определенные внутри пакета Oracle и пытался сопоставить с пользовательских типов.
Я получил следующие вопросы.

При добавлении информации о параметрах в команду Oracle возникает ошибка.
"OCI-22303: type \"STUDENT_PKG\".\"PHONE_RC_TBL\" not found"


При использовании
OracleCommandBuilder.DeriveParameters(command);
Вот это ошибка
OCI-22303: type "KAMI"."STUDENT_PKG" not found


Я попытался создать OracleCustomTypeMapping со следующими именами
- STUDENT_PKG.PHONE_RC_TBL
- STUDENT_PKG
- PHONE_RC_TBL

1 Ответов

Рейтинг:
2

Wendelius

Вместо того чтобы определять тип таблицы внутри заголовка пакета, попробуйте объявить его отдельно и использовать без определения пакета. Иначе говоря

CREATE TYPE PHONE_RC_TBL IS TABLE OF PHONE_TYP_RC;


Также не забудьте удалить все STUDENT_PKG. префиксы из вашего кода


M.Kamran Asim

Спасибо Венделиусу за ваш ответ. UDT на уровне схемы работает нормально. Я уже проверял. Но из-за некоторой процедуры хранения в производстве невозможно переместить типы из пакетов на уровень схемы. Поэтому я должен найти решение для типов пакетов