對於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;
}
您是否嘗試在Oracle Developer Tools for Visual Studio中將ERROR_CODE類型的代碼生成嚮導用作完整性檢查? –
另外,您使用的是哪個版本的ODP.NET? –
@ChristianShay我其實沒有嘗試代碼生成嚮導 - 我會這樣做,並返回一個更新。 它是用於Oracle 12.1(v。4.121.2.0)的ODP.NET(Oracle.DataAccess.dll)的64位非託管版本。 – StefanDK