简体   繁体   中英

Oracle UDTs Custom type mapping for is not specified or is invalid

I got this error, "Custom type mapping for 'ClassXX' is not specified or is invalid. Is it possible that my member value type is not correct to match db UDTs?

Here is my Code:

ClassXX

[OracleCustomTypeMapping("DB.T_OUTERTRAN")]
public class ClassXX: AOracleCustomObject<ClassXX>
{
    [OracleObjectMapping("OUTERSYSTEMCODE")]
    public int OuterSystemCode { get; set; }

    [OracleObjectMapping("TRANSACTIONSOURCE")]
    public int TransactionSource { get; set; }

    [OracleObjectMapping("TRANSACTIONTYPE")]
    public int TransactionType { get; set; }

    [OracleObjectMapping("AMOUNTCHANGE")]
    public decimal AmountChange { get; set; }
    [OracleObjectMapping("REFERENCENO")]
    public string ReferenceNo { get; set; }
    [OracleObjectMapping("REMARKS")]
    public string Remarks { get; set; }
    [OracleObjectMapping("VENDORID")]
    public int VendorId { get; set; }
    [OracleObjectMapping("BUID")]
    public int BuId { get; set; }
    [OracleObjectMapping("USERCODE")]
    public string UserCode { get; set; }
    [OracleObjectMapping("ACCEPTNEGATIVEBALANCE")]
    public int AcceptNegativeBalance { get; set; }

    protected override ClassXX _getObjInstance()
    {
        return this;
    }
}

AOracleCustomObject:

public abstract class AOracleCustomObject<T> : INullable, IOracleCustomTypeFactory, IOracleCustomType
{
    [IgnoreDataMember]
    public bool IsNull
    {
        get
        {
            return false;
        }
    }

    public void FromCustomObject(OracleConnection con, IntPtr pUdt)
    {
        T oracleObj = _getObjInstance();
        PropertyInfo[] properties = typeof(T).GetProperties();
        foreach (PropertyInfo property in properties)
        {
            var attrs = (OracleObjectMappingAttribute[])
                property.GetCustomAttributes(typeof(OracleObjectMappingAttribute), false);
            if (attrs.Length > 0)
            {
                string attrName = attrs[0].AttributeName;
                object value = property.GetValue(oracleObj, null);
                OracleUdt.SetValue(con, pUdt, attrName, value);
            }
        }
    }

    public void ToCustomObject(OracleConnection con, IntPtr pUdt)
    {
        T oracleObj = _getObjInstance();
        PropertyInfo[] properties = typeof(T).GetProperties();
        foreach (PropertyInfo property in properties)
        {
            var attrs = (OracleObjectMappingAttribute[])
                property.GetCustomAttributes(typeof(OracleObjectMappingAttribute), false);
            if (attrs.Length > 0)
            {
                string attrName = attrs[0].AttributeName;
                Type ptype = property.PropertyType;
                object value = Convert.ChangeType(OracleUdt.GetValue(con, pUdt, attrName), ptype);
                property.SetValue(oracleObj, value, null);
            }
        }
    }

    public IOracleCustomType CreateObject()
    {
        return (IOracleCustomType)_getObjInstance();
    }

    protected abstract T _getObjInstance();
}

UDTs:

    create or replace TYPE T_OUTERTRAN AS OBJECT 
( 
  OUTERSYSTEMCODE NUMBER(4,0),
  TRANSACTIONSOURCE NUMBER(4,0),
  TRANSACTIONTYPE   NUMBER(4,0),
  AMOUNTCHANGE NUMBER(26,6),  
  REFERENCENO   VARCHAR2(50 BYTE),
  REMARKS   VARCHAR2(100 BYTE),
  VENDORID  NUMBER(4,0),  
  BUID NUMBER(5,0),
  USERCODE  VARCHAR2(30 BYTE),
  ACCEPTNEGATIVEBALANCE NUMBER(1,0)
);

The Exception log is

    Custom type mapping for 'ClassXX' is not specified or is invalid.
System.InvalidOperationException: Custom type mapping for 'ClassXX' is not specified or is invalid.
   at Oracle.DataAccess.Types.OracleUdt.GetUdtName(String customTypeName, String dataSource)
   at Oracle.DataAccess.Client.OracleParameter.SetUDTFromCustomObject(OracleConnection conn, IOracleCustomType customObj, Int32 i)
   at Oracle.DataAccess.Client.OracleParameter.PreBind_Collection(OracleConnection conn)
   at Oracle.DataAccess.Client.OracleParameter.PreBind(OracleConnection conn, IntPtr errCtx, Int32 arraySize)
   at Oracle.DataAccess.Client.OracleCommand.ExecuteNonQuery()

I tried simple roundtrip and everything seems to work fine.

void Main()
{
    using (var connection = new OracleConnection("DATA SOURCE=HQ_PDB_TCP;PASSWORD=oracle;USER ID=HUSQVIK"))
    {
        connection.Open();

        using (var command = connection.CreateCommand())
        {
            command.CommandText = "DECLARE i SYS.ODCICOST := :p; BEGIN :p := SYS.ODCICOST(i.CPUCOST + 1, i.IOCOST + 1, i.NETWORKCOST + 1, i.INDEXCOSTINFO || 'Dummy'); END;";
            command.BindByName = true;

            var parameter = command.CreateParameter();
            parameter.Direction = ParameterDirection.InputOutput;
            parameter.ParameterName = "p";
            parameter.OracleDbType = OracleDbType.Object;
            parameter.UdtTypeName = "SYS.ODCICOST";
            parameter.Value = new OdciCost { CPUCOST = 123, INDEXCOSTINFO = "DUMMY", IOCOST = 456, NETWORKCOST = 789 };
            command.Parameters.Add(parameter);

            command.ExecuteNonQuery();

            var odciCost = (OdciCost)parameter.Value;
            Console.WriteLine($"CPUCOST={odciCost.CPUCOST}; IOCOST={odciCost.IOCOST}; NETWORKCOST={odciCost.NETWORKCOST}; INDEXCOSTINFO={odciCost.INDEXCOSTINFO}");
        }
    }
}

[OracleCustomTypeMapping("SYS.ODCICOST")]
public class OdciCost : IOracleCustomType, IOracleCustomTypeFactory, INullable
{
    private bool _isNull;
    [OracleObjectMapping("CPUCOST")]
    public decimal CPUCOST;
    [OracleObjectMapping("INDEXCOSTINFO")]
    public string INDEXCOSTINFO;
    [OracleObjectMapping("IOCOST")]
    public decimal IOCOST;
    [OracleObjectMapping("NETWORKCOST")]
    public decimal NETWORKCOST;

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

    public void FromCustomObject(OracleConnection connection, IntPtr pointerUdt)
    {
        OracleUdt.SetValue(connection, pointerUdt, "CPUCOST", CPUCOST);
        OracleUdt.SetValue(connection, pointerUdt, "IOCOST", IOCOST);
        OracleUdt.SetValue(connection, pointerUdt, "NETWORKCOST", NETWORKCOST);
        OracleUdt.SetValue(connection, pointerUdt, "INDEXCOSTINFO", INDEXCOSTINFO);
    }

    public void ToCustomObject(OracleConnection connection, IntPtr pointerUdt)
    {
        CPUCOST = (decimal)OracleUdt.GetValue(connection, pointerUdt, "CPUCOST");
        IOCOST = (decimal)OracleUdt.GetValue(connection, pointerUdt, "IOCOST");
        NETWORKCOST = (decimal)OracleUdt.GetValue(connection, pointerUdt, "NETWORKCOST");
        INDEXCOSTINFO = (string)OracleUdt.GetValue(connection, pointerUdt, "INDEXCOSTINFO");
    }

    public bool IsNull
    {
        get { return this._isNull; }
    }

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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