簡體   English   中英

Oracle和C#-UDT數組作為返回值

[英]Oracle and C# - UDT array as return value

我正在嘗試讓C#讀取PL / SQL用戶定義類型的數組。

這是數組中每個對象的定義:

CREATE OR REPLACE TYPE "REPORTDATUM" AS OBJECT
(
            FIELD1                                                   VARCHAR2(20),
            FIELD2                                                   VARCHAR2(3000),
            FIELD3                                                   NUMBER(15),
            FIELD4                                                   DATE,
            FIELD5                                                   DATE,
            FIELD6                                                   VARCHAR2(4000),
            FIELD7                                                   TIMESTAMP,
            FIELD8                                                   VARCHAR2(10),
            FIELD9                                                   NUMBER(35),
            FIELD10                                                  VARCHAR2(80),
            FIELD11                                                  VARCHAR2(50)
);

CREATE OR REPLACE TYPE "REPORTARRAY" IS TABLE OF REPORTDATUM;

這是我要調用的函數的簽名:

FUNCTION getReport(startTime IN DATE, endTime IN DATE) RETURN REPORTARRAY;

現在,根據我在這里找到的指南: http : //appsjack.blogspot.com/2010/09/pass-custom-udt-types-to-oracle-stored.html

我創建了ReportDatum.cs類,如下所示:

public class ReportDatum : INullable,  IOracleCustomType {

    private bool objectIsNull;

    [OracleObjectMappingAttribute(Constants.ReportDatum.Aliases.Field1)]
    public string Field1 { get; set; }

    [OracleObjectMappingAttribute(Constants.ReportDatum.Aliases.Field2)]
    public string Field2 { get; set; }

                            [...]

    [OracleObjectMappingAttribute(Constants.ReportDatum.Aliases.Field11)]
    public string Field11 { get; set; }


    public static ReportDatum Null {
        get {
            ReportDatum reportDatum = new ReportDatum();
            reportDatum.objectIsNull = true;
            return reportDatum;
        }
    }

    public bool IsNull {
        get { return objectIsNull; }
    }

    public void FromCustomObject(OracleConnection databaseConnection, IntPtr userDefinedTypePointer) {
        if (string.IsNullOrEmpty(this.Field1) == false ) {
            OracleUdt.SetValue(databaseConnection, userDefinedTypePointer, Constants.ReportDatum.Aliases.Field1, this.Field1);
        }
        if (string.IsNullOrEmpty(this.Field2) == false) {
            OracleUdt.SetValue(databaseConnection, userDefinedTypePointer, Constants.ReportDatum.Aliases.Field2, this.Field2);
        }
        [...]
        if (string.IsNullOrEmpty(this.Field11) == false) {
            OracleUdt.SetValue(databaseConnection, userDefinedTypePointer, Constants.ReportDatum.Aliases.Field11, this.Field11);
        }
    }

    public void ToCustomObject(OracleConnection databaseConnection, IntPtr userDefinedTypePointer) {
        this.Field1 = parseString(databaseConnection, userDefinedTypePointer, Constants.ReportDatum.Aliases.Field1);
        this.Field2 = parseString(databaseConnection, userDefinedTypePointer, Constants.ReportDatum.Aliases.Field2);
                                            [...]
        this.Field11 = parseString(databaseConnection, userDefinedTypePointer, Constants.ReportDatum.Aliases.Field11);
    }

    private string parseString(OracleConnection databaseConnection, IntPtr userDefinedTypePointer, string columnName) {
        string valueToReturn = String.Empty;
        try {
            valueToReturn = ( String ) OracleUdt.GetValue(databaseConnection, userDefinedTypePointer, columnName);
        }
        catch (Exception e) {
            error("Exception while attempting to parse string value of column [" + columnName + "]. Message [" + (e == null || e.Message == null ? "NULL" : e.Message) + "]", e);
        }
        return valueToReturn;
    }

 }

我還按照以下步驟創建ReportDatumFactory.cs:

public class ReportDatumFactory : IOracleCustomTypeFactory {

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

}

根據我上面鏈接的指南,這足以處理組成數組的每個項目。

為了處理數組本身,我創建了以下類。

ReportArray.cs

public class ReportArray : INullable, IOracleCustomType {

    [OracleArrayMapping()]
    public ReportDatum[] reportArray;

    private bool objectIsNull;

    public bool IsNull {
        get { return objectIsNull; }
    }

    public void FromCustomObject(OracleConnection databaseConnection, IntPtr userDefinedTypePointer) {
        try {
            OracleUdt.SetValue(databaseConnection, userDefinedTypePointer, 0, reportArray);
        }
        catch (Exception e) {
            error("Exception while populating OracleUdt from ReportArray.", e);
        }
    }

    public void ToCustomObject(OracleConnection databaseConnection, IntPtr userDefinedTypePointer) {
        try {
            reportArray = ( ReportDatum[] ) OracleUdt.GetValue(databaseConnection, userDefinedTypePointer, 0);
        }
        catch (Exception e) {
            error("Exception while reading values from OracleUdt related to ReportArray.", e);
        }
    }

}         

和相關的工廠類

ReportArrayFactory.cs

public class ReportArrayFactory : IOracleCustomTypeFactory, IOracleArrayTypeFactory {

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


    public Array CreateArray(int numberOfElements) {
        return new ReportArray[numberOfElements];
    }

    public Array CreateStatusArray(int numberOfElements) {
        return null;
    }

}

現在,關於調用存儲過程的方法,這就是我所擁有的:

Report.cs

    private void executeStoredProcedure2(OracleConnection databaseConnection, string schema, string storedProcedureName, DateTime startTime, DateTime endTime, int numberOfElements) {
        OracleCommand databaseCommand = new OracleCommand();
        ReportArray reportArray = new ReportArray();

        debug("Attempting to populate the report array");
        if (databaseConnection != null && databaseConnection.State == ConnectionState.Open) {
            try {
                databaseCommand.Connection = databaseConnection;
                databaseCommand.CommandType = CommandType.StoredProcedure;
                databaseCommand.CommandText = schema + "." + storedProcedureName;
                databaseCommand.Parameters.Add(createUserDefinedParameter(numberOfElements, reportArray));
                databaseCommand.Parameters.Add(Constants.ReportDatum.ParameterNames.startTime, OracleDbType.Date, startTime, ParameterDirection.Input);
                databaseCommand.Parameters.Add(Constants.ReportDatum.ParameterNames.endTime, OracleDbType.Date, endTime, ParameterDirection.Input);
                databaseCommand.ExecuteNonQuery();
                //How do I populate the reportArray object?
            }
            catch (Exception exception) {
                error("Exception while executing stored procedure [" + storedProcedure2 + "].", exception);
            }
            finally {
                databaseCommand.Dispose();
            }
        }
    }



    private OracleParameter createUserDefinedParameter(int size, ReportArray reportArray) {
        OracleParameter valueToReturn = null;
        try {
            valueToReturn = new OracleParameter();
            valueToReturn.ParameterName = "reportData"; //this is the name of the REPORTARRAY object in the Oracle function that is being returned.
            valueToReturn.OracleDbType = OracleDbType.Array;
            valueToReturn.Direction = ParameterDirection.ReturnValue;
            valueToReturn.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
            valueToReturn.UdtTypeName = Constants.ReportDatum.arrayDataTypeDefinition;
            valueToReturn.ArrayBindSize = new int[size];
            valueToReturn.ArrayBindStatus = new OracleParameterStatus[size];
            valueToReturn.Size = size;
            valueToReturn.Value = reportArray.reportArray;
        }
        catch (Exception e) {
            error("Exception while attempting to create user defined parameter.", e);
        }
        return valueToReturn;
    }

我面臨的問題是我無法使用C#返回數組。 有人遇到過這個問題嗎? 我想念什么?

我有理由相信SQL代碼可以正常工作。 目前只有C#產生了問題。

看起來有些錯誤。

首先,工廠需要OracleCustomTypeMapping屬性。 沒有它們,Oracle將根本不會使用這些映射工廠類:

    [OracleCustomTypeMapping("SCHEMA.REPORTDATUM")]
    public class ReportDatum ...

    [OracleCustomTypeMapping("SCHEMA.REPORTARRAY")]
    public class ReportArray ...

其次,數組映射工廠存在一個錯誤:創建數組時,您要創建一個ReportDatum對象數組。 目前,您正在創建一個ReportArray對象數組,即不需要的數組數組。 換句話說,替換

    public Array CreateArray(int numberOfElements) {
        return new ReportArray[numberOfElements];
    }

    public Array CreateArray(int numberOfElements) {
        return new ReportDatum[numberOfElements];
    }

第三,刪除行

        CollectionType = OracleCollectionType.PLSQLAssociativeArray,

從您的createUserDefinedParameter方法。 返回的值不是PL / SQL關聯數組(它是另一種集合),因此不應使用此屬性。 如果使用此屬性,則可能會發現從存儲函數返回的返回值是一個空的object數組。

最后,要從存儲的函數調用中獲取數組,請在對databaseCommand.ExecuteNonQuery()的調用之后添加以下行:

    reportArray = (ReportArray)databaseCommand.Parameters["reportData"].Value;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM