ORACLE HANDBOOK系列之六:ODP.NET与复杂的PL/SQL数据类型(Using ODP.NET To Deal With Complex PLSQL Data Types)...
在開始介紹之前,先給出文章里用到的所有PL/SQL代碼:
(類型定義)
?
CREATE?OR?REPLACE?TYPE?T_Nested_Tab_Str?IS?TABLE?OF?VARCHAR2(25);--
CREATE?OR?REPLACE?TYPE?T_Object?IS?OBJECT
(
?employee_id?number(6),
?last_name?varchar2(25)
);
--
CREATE?OR?REPLACE?TYPE?T_VARRAY_STR?IS?VARRAY(10)?OF?VARCHAR2(25);
--
CREATE?OR?REPLACE?TYPE?T_Nested_Tab_Obj?IS?TABLE?OF?T_Object;
(包的聲明)
?
CREATE?OR?REPLACE?PACKAGE?pkg_odp_dotnet?IS?TYPE?T_Ref_Cursor?IS?REF?CURSOR;
?TYPE?T_Asso_Array_Num?IS?TABLE?OF?employees_bk.employee_id%TYPE?INDEX?BY?PLS_INTEGER;
?TYPE?T_Asso_Array_Str?IS?TABLE?OF?employees_bk.last_name%TYPE?INDEX?BY?PLS_INTEGER;?
?--
?PROCEDURE?proc_ref_cursor(p_ref_cursor?OUT?T_Ref_Cursor);
?PROCEDURE?proc_sys_refcursor(p_sys_refcursor?OUT?SYS_REFCURSOR);
?--
?PROCEDURE?proc_asso_array_num_in(p_asso_array_num????IN?T_Asso_Array_Num);
?PROCEDURE?proc_asso_array_num_out(p_asso_array_num?OUT?T_Asso_Array_Num);
?PROCEDURE?proc_asso_array_str_out(p_asso_array_str?OUT?T_Asso_Array_Str);
?--
?PROCEDURE?proc_nested_tab_str_in(p_nested_tab_str?IN?T_Nested_Tab_Str);
?PROCEDURE?proc_nested_tab_str_out(p_nested_tab_str?OUT?T_Nested_Tab_Str);
?--
?PROCEDURE?proc_obj_in(p_obj?IN?T_Object);
?--
?PROCEDURE?proc_nested_tab_obj_in(p_nested_tab_obj?IN?T_Nested_Tab_Obj);
?--
?PROCEDURE?proc_varray_str_in(p_varray_str?IN?T_Varray_Str);
END;
(包體)
?
CREATE?OR?REPLACE?PACKAGE?BODY?pkg_odp_dotnet?IS?/*This?proc?is?invoked?by?.NET?to?test?the?ref?cursor
????Retrieve?the?employees?whose?id?less?than?105*/
?PROCEDURE?proc_ref_cursor(p_ref_cursor?OUT?T_Ref_Cursor)
?IS
?BEGIN
????OPEN?p_ref_cursor?FOR
????SELECT?employee_id,first_name,last_name?FROM?employees_bk?WHERE?employee_id<105;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?pre-defined?sys_refcursor
????Retrieve?the?employees?whose?id?less?than?105*/
?PROCEDURE?proc_sys_refcursor(p_sys_refcursor?OUT?SYS_REFCURSOR)
?IS
?BEGIN
????OPEN?p_sys_refcursor?FOR
????SELECT?employee_id,first_name,last_name?FROM?employees_bk?WHERE?employee_id<105;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?input?parameter?with?the?type?of?associative?array,?
????and?the?type?of?the?collection?element?is?number
????Loop?through?each?employee?id?in?the?given?associative?array,?then?update?its?salary*/
?PROCEDURE?proc_asso_array_num_in(p_asso_array_num????IN?T_Asso_Array_Num)
?IS
????idx?PLS_INTEGER;
?BEGIN
????idx:=p_asso_array_num.FIRST;
????WHILE(idx?IS?NOT?NULL)?LOOP
??????UPDATE?employees_bk?SET?salary=salary+1?WHERE?employee_id=p_asso_array_num(idx);
??????idx:=p_asso_array_num.NEXT(idx);
????END?LOOP;
????COMMIT;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?output?parameter?with?the?type?of?associative?array,?
????and?the?type?of?the?collection?element?is?varchar2
????Retrieve?the?employees?whose?id?less?than?105*/
?PROCEDURE?proc_asso_array_str_out(p_asso_array_str?OUT?T_Asso_Array_Str)
?IS
?BEGIN
????SELECT?last_name?BULK?COLLECT?INTO?p_asso_array_str?FROM?employees_bk?WHERE?employee_id<105;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?output?parameter?with?the?type?of?associative?array,?
????and?the?type?of?the?collection?element?is?number
????Retrieve?the?employees?whose?id?less?than?105*/
?PROCEDURE?proc_asso_array_num_out(p_asso_array_num?OUT?T_Asso_Array_Num)
?IS
?BEGIN
????SELECT?employee_id?BULK?COLLECT?INTO?p_asso_array_num?FROM?employees_bk?WHERE?employee_id<105;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?input?parameter?with?the?type?of?nested?table,?
????and?the?type?of?the?collection?element?is?number
????Loop?through?each?last?name?in?the?given?nested?table,?then?update?its?salary*/
?PROCEDURE?proc_nested_tab_str_in(p_nested_tab_str?IN?T_Nested_Tab_Str)
?IS
?BEGIN
????FORALL?i?IN?p_nested_tab_str.FIRST..p_nested_tab_str.LAST
?????UPDATE?employees_bk?SET?salary=salary+1?WHERE?last_name=p_nested_tab_str(i);
????COMMIT;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?output?parameter?with?the?type?of?nested?table,?
????and?the?type?of?the?collection?element?is?varchar2
????Retrieve?the?employees?whose?id?less?than?105*/
?PROCEDURE?proc_nested_tab_str_out(p_nested_tab_str?OUT?T_Nested_Tab_Str)
?IS
?BEGIN
????SELECT?last_name?BULK?COLLECT?INTO?p_nested_tab_str?FROM?employees_bk?WHERE?employee_id<105;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?output?parameter?with?the?type?of?VARRAY,?
????and?the?type?of?the?collection?element?is?varchar2
????Loop?through?each?last?name?in?the?given?varray,?then?update?its?salary*/
?PROCEDURE?proc_varray_str_in(p_varray_str?IN?T_Varray_Str)
?IS
?BEGIN
????FORALL?i?IN?p_varray_str.FIRST..p_varray_str.LAST
??????UPDATE?employees_bk?SET?salary=salary+1?WHERE?last_name=p_varray_str(i);
????COMMIT;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?output?parameter?with?the?type?of?object
????Update?the?last_name?according?to?two?fields?last_name,?employee_id?in?the?given?object*/
?PROCEDURE?proc_obj_in(p_obj?IN?T_Object)
?IS
?BEGIN
????UPDATE?employees_bk?SET?last_name=p_obj.last_name?WHERE?employee_id=p_obj.employee_id;
????COMMIT;
?END;
?
?---------------------------------------------------------------------------------------------------------------------------------
?/*This?proc?is?invoked?by?.NET?to?test?the?output?parameter?with?the?type?of?nested?table,?
????and?the?type?of?the?collection?element?is?object
????Loop?through?each?object?in?the?given?nested?table,?then?update?the?last?name?of?employee*/
?PROCEDURE?proc_nested_tab_obj_in(p_nested_tab_obj?IN?T_Nested_Tab_Obj)
?IS
?BEGIN
????FORALL?idx?IN?p_nested_tab_obj.FIRST..p_nested_tab_obj.LAST
??????UPDATE?employees_bk?SET?last_name=p_nested_tab_obj(idx).last_name?WHERE?employee_id=p_nested_tab_obj(idx).employee_id;
????COMMIT;
?END;
END;
?
1.引用游標(REF Cursor)
引用游標作為輸出參數的情況十分常見。相較于MS SQL Server,Oracle存儲過程無法直接返回結果集,而需要借助REF Cursor。REF Cursor實際上是指向服務器內存的指針,也就是說客戶端調用獲取的是一個指針,它指向服務器內存中的結果集數據。
雖然可能令熟悉MS SQL Server平臺的開發者困惑,但是使用REF Cursor帶來兩個明顯的好處:1)它可以延遲數據的交付,客戶端獲取的只是指針,數據只有在被請求時才傳遞;2)使用REF Cursor在存儲過程之間傳遞結果集,可以最小化對性能影響,畢竟傳遞的只是指針而不是真實數據。
(使用DataReader)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_ref_cursor";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_ref_cursor";
op.Direction?=?ParameterDirection.Output;
op.OracleDbType?=?OracleDbType.RefCursor;
cmd.Parameters.Add(op);
OracleDataReader?odr?=?cmd.ExecuteReader();
//
if?(odr.HasRows)
{
????while?(odr.Read())
????{
????????string?s?=?odr.GetDecimal(odr.GetOrdinal("employee_id"))?+?"?"
????????????+?odr.GetString(odr.GetOrdinal("first_name"))?+?"?"
????????????+?odr.GetString(odr.GetOrdinal("last_name"));
????????Console.WriteLine(s);
????}
}
(使用DataAdapter)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_ref_cursor";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_ref_cursor";
op.Direction?=?ParameterDirection.Output;
op.OracleDbType?=?OracleDbType.RefCursor;
cmd.Parameters.Add(op);
OracleDataAdapter?oda?=?new?OracleDataAdapter(cmd);
DataSet?ds?=?new?DataSet();
oda.Fill(ds);
//
for?(int?i?=?0;?i?<?ds.Tables[0].Rows.Count;?i++)
{
????string?s?=?ds.Tables[0].Rows[i]["employee_id"]?+?"?"
????????????+?ds.Tables[0].Rows[i]["first_name"]?+?"?"
????????????+?ds.Tables[0].Rows[i]["last_name"];
????Console.WriteLine(s);
}
注意上面的Tables[0],如果有多個輸出參數是REF Cursor,則可以使用Tables[0]、Tables[1],以此類推。DataReader似乎無法在有多個輸出的REF Cursor有情況下使用。
方便起見,可以使用Oracle預定義的SYS_REFCURSOR,這樣可以省去TYPE定義。在用法上與自定義的REF Cursor相同,就不再舉具體的實例了。
?
2.關聯數組(Associative array)
關于PL/SQL中的集合類型,已經在上一篇文章《ORACLE HANDBOOK系統之三:PL/SQL中的集合類型(COLLECTIONS IN PL/SQL)》中介紹了(http://www.cnblogs.com/KissKnife/archive/2011/04/07/2008158.html),這里介紹C#與Oracle交互時如何使用關聯數組。
(作為輸入參數)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_asso_array_num_in";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_asso_array_num";
op.Direction?=?ParameterDirection.Input;
op.OracleDbType?=?OracleDbType.Decimal;
//
op.CollectionType?=?OracleCollectionType.PLSQLAssociativeArray;
op.Value?=?new?decimal[]?{?100,?101,?102?};
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
相應的,如果定義的Associative array的元素是Varchar2,則OracleParameter.OracleDbType就是OracleDbType.Varchar2,為OracleParameter.value賦值要使用string[]。
(作為輸出參數)
?
using?Oracle.DataAccess.Types;…
cmd.CommandText?=?"pkg_odp_dotnet.proc_asso_array_str_out";
cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_asso_array_str";
op.Direction?=?ParameterDirection.Output;
op.OracleDbType?=?OracleDbType.Varchar2;
//
op.CollectionType?=?OracleCollectionType.PLSQLAssociativeArray;
//
op.Size?=?12;
int[]?iArray?=?new?int[op.Size];
for?(int?i?=?0;?i?<?iArray.Length;?i++)
{
????iArray[i]?=?25;
}
op.ArrayBindSize?=?iArray;
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
//
OracleString[]?osArray?=?(OracleString[])op.Value;
for?(int?i?=?0;?i?<=?osArray.GetUpperBound(0);?i++)
{
????Console.WriteLine(osArray[i].Value?+?",");
}
OracleParameter.Size,如果給定的Size比實際查詢所得的行數小,則會報ORA-06513錯誤,所以如果無法確定實際返回的集合長度,需要往大了取。
OracleParameter.ArrayBindSize,這里集合元素是變長的VARCHAR2,因此需要為每個元素指定其長度,由于表中last_name的長度是25,所以這里定義成了25,比25小不會報錯,但是可能導致字符串被截斷。如果要返回的集合元素是NUMBER,則可以不指定ArrayBindSize,
OracleString,不要天真地以為可以使用string[]數組來接收返回的集合,NO!需要OracleString[],使用string[]將導致轉化出錯。如果要返回的集合元素是NUMBER,通常用OracleDecimal[]而不能直接用decimal[]。
通常來說,以集合類型作為輸出參數類型的情況相對較少,對于結果集,使用REF Cursor是更好的選擇。
?
3.嵌套表(Nested table)
對于Nested table,有兩種方案可以選擇,1)直接映射成C#中的數組,2)映射成C#的自定義類型。
第一種方案,需要首先聲明一個Factory類并實現IOracleArrayTypeFactory接口,并使用OracleCustomTypeMappingAttribute(schema.type_name)指定需要映射的Nested table的名稱,schema.type_name需要大寫。
可以看到我們使用了OracleDbType.Array,并且指定了參數的UdtTypeName。賦值時直接使用了string[]。
[OracleCustomTypeMappingAttribute("HR.T_NESTED_TAB_STR")]public?class?Nested_Tab_Mapping_To_Array_Factory?:?IOracleArrayTypeFactory
{
????public?Array?CreateArray(int?i)
????{
????????return?new?string[i];
????}
????//
????public?Array?CreateStatusArray(int?i)
????{
????????return?new?OracleUdtStatus[i];
????}
}
(作為輸入參數)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_nested_tab_str_in";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_nested_tab_str";
op.Direction?=?ParameterDirection.Input;
op.OracleDbType?=?OracleDbType.Array;
op.UdtTypeName?=?"HR.T_NESTED_TAB_STR";
op.Value?=?new?string[]?{?"King",?"Olsen"?};
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
(作為輸出參數,同樣需要上面的Factory類)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_nested_tab_str_out";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_nested_tab_str";
op.Direction?=?ParameterDirection.Output;
op.OracleDbType?=?OracleDbType.Array;
op.UdtTypeName?=?"HR.T_NESTED_TAB_STR";
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
//
if?(op.Value?!=?DBNull.Value)
{
????string[]?result?=?(string[])op.Value;
????foreach?(string?s?in?result)
????{
????????Console.WriteLine(s);
????}
}
對比而言,第一種方案中將Nested table映射成C#數組的做法更簡潔。下面我們介紹第二種方案,稍微繁雜一點,除了需要Factory類(需要同時實現IOracleArrayTypeFactory與IOracleCustomTypeFactory兩個接口)外,它還需要一個自定義類型:
[OracleCustomTypeMappingAttribute("HR.T_NESTED_TAB_STR")]public?class?Nested_Tab_Mapping_To_Object_Factory?:?IOracleCustomTypeFactory,?IOracleArrayTypeFactory
{
????public?IOracleCustomType?CreateObject()
????{
????????return?new?Nested_Tab_Mapping_To_Object();
????}
????//
????public?Array?CreateArray(int?i)
????{
????????return?new?String[i];
????}
????//
????public?Array?CreateStatusArray(int?i)
????{
????????return?new?OracleUdtStatus[i];
????}
}
?
public?class?Nested_Tab_Mapping_To_Object?:?IOracleCustomType,?INullable
{
????[OracleArrayMapping()]
????public?string[]?container;
????//
????private?OracleUdtStatus[]?statusArray;
????public?OracleUdtStatus[]?StatusArray
????{
????????get
????????{
????????????return?statusArray;
????????}
????????set
????????{
????????????statusArray?=?value;
????????}
????}
????//
????private?bool?isNull;
????public?bool?IsNull
????{
????????get
????????{
????????????return?isNull;
????????}
????}
????//
????public?static?Nested_Tab_Mapping_To_Object?Null
????{
????????get
????????{
????????????Nested_Tab_Mapping_To_Object?nt?=?new?Nested_Tab_Mapping_To_Object();
????????????nt.isNull?=?true;
????????????return?nt;
????????}
????}
????//
????public?void?ToCustomObject(OracleConnection?conn,?IntPtr?pUdt)
????{
????????object?outStatusArray;
????????container?=?(string[])OracleUdt.GetValue(conn,?pUdt,?0,?out?outStatusArray);
????????statusArray?=?(OracleUdtStatus[])outStatusArray;
????}
????public?void?FromCustomObject(OracleConnection?conn,?IntPtr?pUdt)
????{
????????OracleUdt.SetValue(conn,?pUdt,?0,?container,?statusArray);
????}
}
(作為輸入參數)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_nested_tab_str_in";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_nested_tab_str";
op.Direction?=?ParameterDirection.Input;
op.OracleDbType?=?OracleDbType.Object;
op.UdtTypeName?=?"HR.T_NESTED_TAB_STR";
Nested_Tab_Mapping_To_Object?nt?=?new?Nested_Tab_Mapping_To_Object();
nt.container?=?new?string[]?{?"King",?"Olsen"?};
op.Value?=?nt;
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
(作為輸出參數)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_nested_tab_str_out";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_nested_tab_str";
op.Direction?=?ParameterDirection.Output;
op.OracleDbType?=?OracleDbType.Object;
op.UdtTypeName?=?"HR.T_NESTED_TAB_STR";
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
//
if?(op.Value?!=?DBNull.Value)
{
????Nested_Tab_Mapping_To_Object?o?=?(Nested_Tab_Mapping_To_Object)op.Value;
????foreach?(string?s?in?o.container)
????{
????????Console.WriteLine(s);
????}
}
?
4.動態數組(VARRAY)
與Nested table用法相同。
?
5.對象(Object)
Oracle中Object類型的定義可以參見文章開頭的T_Object。遇到T_Object時,處理起來類似于第4節中將Nested table映射成自定義對象的情況,同樣需要一個自定義類型以及一個Factory類。
[OracleCustomTypeMappingAttribute("HR.T_OBJECT")]public?class?Ora_Object_Factory?:?IOracleCustomTypeFactory
{
????public?virtual?IOracleCustomType?CreateObject()
????{
????????Ora_Object?o?=?new?Ora_Object();
????????return?o;
????}
}
?
public?class?Ora_Object?:?IOracleCustomType,?INullable
{
????private?bool?isNull;
????private?int?employeeId;
????private?string?lastName;
????//
????public?bool?IsNull
????{
????????get
????????{
????????????return?this.isNull;
????????}
????}
????//
????public?static?Ora_Object?Null
????{
????????get
????????{
????????????Ora_Object?mo?=?new?Ora_Object();
????????????mo.isNull?=?true;
????????????return?mo;
????????}
????}
????//
????[OracleObjectMappingAttribute("EMPLOYEE_ID")]
????public?int?EmployeeId
????{
????????get
????????{
????????????return?employeeId;
????????}
????????set
????????{
????????????employeeId?=?value;
????????}
????}
????//
????[OracleObjectMappingAttribute("LAST_NAME")]
????public?string?LastName
????{
????????get
????????{
????????????return?lastName;
????????}
????????set
????????{
????????????lastName?=?value;
????????}
????}
????//
????public?void?FromCustomObject(Oracle.DataAccess.Client.OracleConnection?conn,?System.IntPtr?pUdt)
????{
????????OracleUdt.SetValue(conn,?pUdt,?"EMPLOYEE_ID",?this.EmployeeId);
????????OracleUdt.SetValue(conn,?pUdt,?"LAST_NAME",?this.LastName);
????}
????public?void?ToCustomObject(Oracle.DataAccess.Client.OracleConnection?conn,?System.IntPtr?pUdt)
????{
????????this.EmployeeId?=?((int)(OracleUdt.GetValue(conn,?pUdt,?"EMPLOYEE_ID")));
????????this.LastName?=?((string)(OracleUdt.GetValue(conn,?pUdt,?"LAST_NAME")));
????}
}
(作為輸入參數)
?
cmd.CommandText?=?"pkg_odp_dotnet.proc_obj_in";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_obj";
op.Direction?=?ParameterDirection.Input;
op.OracleDbType?=?OracleDbType.Object;
op.UdtTypeName?=?"HR.T_OBJECT";
//
Ora_Object?mo?=?new?Ora_Object();
mo.EmployeeId?=?100;
mo.LastName?=?"abcd";
op.Value?=?mo;
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
作為輸出參數的情況很簡單,這里就不重復了。
?
6.對象集合(Object collection)
來到終極篇,所謂對象集合,這里指的是本身是個集合類型,并且集合元素是Oracle的Object,例如我們在最開始定義的T_Nested_Tab_Obj。
由于它是Nested table,則我們可以按照第3節中的作法將其轉化成C#中的Array,于是,我們需要一個Factory類并實現IOracleArrayTypeFactory接口:
[OracleCustomTypeMappingAttribute("HR.T_NESTED_TAB_OBJ")]public?class?Nested_Tab_Obj_Mapping_To_Array_Factory?:?IOracleArrayTypeFactory
{
????public?Array?CreateArray(int?i)
????{
????????return?new?Ora_Object[i];
????}
????//
????public?Array?CreateStatusArray(int?i)
????{
????????return?new?OracleUdtStatus[i];
????}
}
又由于集合的元素是Oracle的Object類型,仿照第5節中的做法,我們分別需要一個自定義類型以及一個Factory類,由于集合元素也是使用的T_Object,所以這兩個類與第5節中相同,這里不再重復寫了。下面我們看看具體的調用代碼:
cmd.CommandText?=?"pkg_odp_dotnet.proc_nested_tab_obj_in";cmd.CommandType?=?CommandType.StoredProcedure;
//
OracleParameter?op?=?new?OracleParameter();
op.ParameterName?=?"p_nested_tab_obj";
op.Direction?=?ParameterDirection.Input;
op.OracleDbType?=?OracleDbType.Array;
op.UdtTypeName?=?"HR.T_NESTED_TAB_OBJ";
//
Ora_Object?mo?=?new?Ora_Object();
mo.EmployeeId?=?100;
mo.LastName?=?"00000";
Ora_Object?mo2?=?new?Ora_Object();
mo2.EmployeeId?=?102;
mo2.LastName?=?"00000";
op.Size?=?2;
op.Value?=?new?Ora_Object[]?{?mo,?mo2?};
//
cmd.Parameters.Add(op);
cmd.ExecuteNonQuery();
作為輸出參數的情況也很容易寫,這里就不舉例子了,VARRAY的情況與Nested table基本一樣,也不舉例了。到這里,關于在C#中如何處理幾類主要的復雜參數類型,已經基本介紹完了,對于一些更為復雜的,比如Object中包含Object等等情況,不太常見,就不介紹了。
PS,雖然Associative array中的元素也可以是Object,但在與C#類型做映射時似乎不能成功,可能根Associative array是PL/SQL類型(即不能通過CREATE TYPE創建獨立的類型)有關,還沒有找到相關的文檔。
?
?
總結
以上是生活随笔為你收集整理的ORACLE HANDBOOK系列之六:ODP.NET与复杂的PL/SQL数据类型(Using ODP.NET To Deal With Complex PLSQL Data Types)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux下,.ko,.o , .so
- 下一篇: 莱斯大学找到了多被提升3G/4G网络性能