2015-06-25 56 views
0

對於UDT(用戶定義類型)行爲,我在Odp.net上遇到了一些麻煩。當我有包含返回特定UDT一個OUT參數的過程如何讓ODP.NET從Oracle存儲過程中的out參數返回用戶定義類型的空值?

我的問題就出現了。

當我返回爲OUT參數實例化的UDT沒有問題

當我回到NULL值爲OUT參數我得到一個錯誤NullReference

類型的第一個機會異常 'System.NullReferenceException' 發生在Oracle.DataAccess.dll

我已經嘗試在相關的OracleCommand參數上設置IsNullable = True,但沒有任何成功。

我沒有問題發送和接收相當複雜的UDT,例如UDT具有嵌套的UDT和對象集合以及UDT的嵌套對象集合。

任何想法,如果這可以使用ODP.NET解決,而不是讓Oracle過程返回對象類型的一個實例?

UPDATE - 解決:

的問題是,其嵌套UDT類型的UDT類型不正確初始化爲null。使用自動生成的代碼解決了問題。 Using Oracle User-Defined Types with .NET and Visual Studio

基督教吉文,謝謝你解決問題 - 自動生成的代碼 也許比實現基類來處理 大部分行爲的更好的選擇,雖然這是可能的。

的Oracle存儲過程的簽名是:

using (var oCmd = new OracleCommand 
     { 
      CommandText = "MYSCHEMA.MYPACKAGE.CREATE_DEFINITIONS_FOR_GROUP", 
      Connection = oConn, 
      CommandType = CommandType.StoredProcedure 
     }) 
{ 
    try 
    { 
     oCmd.Parameters.Add(OracleParameterFactory.CreateInParam(
      "P_GRP_NO", OracleDbType.Int64, value: groupNo)); 
     oCmd.Parameters.Add(OracleParameterFactory.CreateInParam(
      "P_DATE", OracleDbType.Date, value: dateOfGroup)); 
     oCmd.Parameters.Add(OracleParameterFactory.CreateOutParamForUdtType(
      "P_ERROR_CODE", "MYSCHEMA.ERROR_CODE")); 

     oCmd.ExecuteNonQuery(); 

     var report = oCmd.Parameters["P_ERROR_CODE"].Value as DbErrorCode; 

     return report; 
    } 
    finally 
    { 
     CommandHelpers.DisposeParameters(oCmd); 
    } 
} 

的UDT類型被定義爲有效的:

PROCEDURE CREATE_DEFINITIONS_FOR_GROUP(
    P_GRP_NO    IN  NUMBER 
    ,P_DATE    IN  DATE 
    ,P_ERROR_CODE   OUT MYSCHEMA.ERROR_CODE); 

我使用打開連接後ODP.NET調用這個代碼在C# UDT輸入。NET這樣的:

public class DbErrorCode : TypeTemplate 
{ 
    [OracleObjectMapping("ERROR_CODE")] 
    public decimal Code { get; set; } 

    [OracleObjectMapping("DESCRIPTION")] 
    public string Description { get; set; } 
} 

基座TypeTemplate類的定義如下:

public class TypeTemplate : IOracleCustomType, INullable 
{ 
    public virtual void FromCustomObject(OracleConnection con, IntPtr pUdt) 
    { 
     foreach (var p in GetType().GetProperties()) 
     { 
      // Must ignore these two properties 
      if (p.Name == "Null" || p.Name == "IsNull") continue; 

      var oracleObjectMappingAttribute = p.GetCustomAttributes(typeof(OracleObjectMappingAttribute), false)[0] as OracleObjectMappingAttribute; 

      if (oracleObjectMappingAttribute == null) continue; 

      var attributeName = oracleObjectMappingAttribute.AttributeName; 

      if (p.GetCustomAttributes(typeof(IgnoreAttribute), false).Length == 0) 
      { 
       if (p.GetCustomAttributes(typeof(NullableAttribute), false).Length == 0) 
       { 
        OracleUdt.SetValue(con, pUdt, attributeName, p.GetValue(this, null)); 
       } 
       else 
       { 
        if (p.GetValue(this, null) != null) 
        { 
         OracleUdt.SetValue(con, pUdt, attributeName, p.GetValue(this, null)); 
        } 
       } 
      } 
     } 
    } 

    public virtual void ToCustomObject(OracleConnection con, IntPtr pUdt) 
    { 
     foreach (var p in GetType().GetProperties()) 
     { 
      // Must ignore these two properties 
      if (p.Name == "Null" || p.Name == "IsNull") continue; 

      var oracleObjectMappingAttribute = p.GetCustomAttributes(typeof(OracleObjectMappingAttribute), false)[0] as OracleObjectMappingAttribute; 

      if (oracleObjectMappingAttribute == null) continue; 

      var attributeName = oracleObjectMappingAttribute.AttributeName; 

      if (!OracleUdt.IsDBNull(con, pUdt, attributeName)) 
      { 
       p.SetValue(this, OracleUdt.GetValue(con, pUdt, attributeName), null); 
      } 
     } 
    } 

    #region INullable Members 

    public bool IsNull { get; private set; } 

    public static TypeTemplate Null 
    { 
     get 
     { 
      var obj = new TypeTemplate { IsNull = true }; 
      return obj; 
     } 
    } 

    #endregion 
} 

爲UDT參數在OracleParameterFactory的方法如下(異常處理從代碼移除,以表現爲乾淨的代碼儘可能地 - 產生的錯誤並非來自異常處理):

public static OracleParameter CreateOutParamForUdtType(
    string paramName, string udtName, object value, bool isNullable = false) 
{ 
    var param = new OracleParameter 
    { 
     ParameterName = paramName, 
     UdtTypeName = udtName.ToUpperInvariant(), 
     OracleDbType = OracleDbType.Object, 
     Direction = ParameterDirection.Output, 
     IsNullable = isNullable 
    }; 

    if (value != null) 
    { 
     param.Value = value; 
    } 

    return param; 
} 
+0

您是否嘗試在Oracle Developer Tools for Visual Studio中將ERROR_CODE類型的代碼生成嚮導用作完整性檢查? –

+0

另外,您使用的是哪個版本的ODP.NET? –

+0

@ChristianShay我其實沒有嘗試代碼生成嚮導 - 我會這樣做,並返回一個更新。 它是用於Oracle 12.1(v。4.121.2.0)的ODP.NET(Oracle.DataAccess.dll)的64位非託管版本。 – StefanDK

回答

1

問題解決:問題是UDT類型及其嵌套的UDT類型未正確初始化爲空。使用自動生成的代碼解決了problem.Using Oracle用戶定義類型與.NET和Visual Studio

基督教吉文,謝謝你解決問題 - 自動生成的代碼也許是比實現基類是更好的選擇以處理大部分行爲,儘管這是可能的。

0

我不是這個肯定的,但我的經驗是,「oCmd.ExecuteNonQuer y()「可能返回null,並且需要返回給對象,然後可以檢查它是否爲空,並返回並清空UDT或返回的on。嘗試

TypeTemplate udtOnbj = new TypeTemplate();

object testObj = oCmd.ExecuteNonQuery();

if(testObj == null){return udtObj; } else {return testObj; }

+0

不幸的是,這不起作用@NicholasSwandel - 我試了一下。這是對oCmd.ExecuteNonQuery()的調用失敗,所以即使我設置了一個變量,也不會繞過將它的值賦給變量。 – StefanDK

相關問題