国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

使用 ADO.NET 訪問 Oracle 9i 存儲過程

2024-07-10 13:11:35
字體:
供稿:網(wǎng)友

  摘要:使用 microsoft .net 框架 1.1 中的 microsoft .net oracle 提供程序訪問 oracle 存儲過程和函數(shù)。

  本文討論了如何使用 ado.net 訪問 oracle 存儲過程(稱為 sql 編程塊)和函數(shù)(返回單個值的編程塊)。

  您可以使用以下托管數(shù)據(jù)提供程序連接到 oracle 數(shù)據(jù)庫:microsoft .net oracle 提供程序、ole db .net 提供程序、odbc .net 數(shù)據(jù)提供程序以及 oracle 的 odp.net 提供程序。本文使用用于 oracle 的 microsoft?.net 框架數(shù)據(jù)提供程序。使用 oracle odp.net 數(shù)據(jù)提供程序或用于 ole db 的 microsoft .net 框架數(shù)據(jù)提供程序時可使用不同的功能。

  oracle .net 數(shù)據(jù)提供程序隨 .net 框架 1.1 一起提供。如果您使用的是 .net 框架 1.0,您將需要下載 .net managed provider for oracle。無論是哪個版本,數(shù)據(jù)提供程序類都位于 system.data.oracleclient 命名空間中。

  概述

  pl/sql 是 sql 的 oracle 實現(xiàn)。它與 microsoft?sql server? 所使用的 t-sql 類似,但也有一些不同之處,本文稍后對此進(jìn)行了詳細(xì)討論。與 t-sql 一樣,pl/sql 擴(kuò)展了標(biāo)準(zhǔn) sql。pl/sql 用于定義命名編程塊,如存儲過程、函數(shù)和觸發(fā)器。

  類

  可使用 system.data.oracleclient 命名空間中類的子集來執(zhí)行 oracle 存儲過程和函數(shù)。下表對這些類進(jìn)行了說明:

說明

oraclecommand

針對 oracle 數(shù)據(jù)庫執(zhí)行的存儲過程的 sql 語句。

oracleconnection

打開的數(shù)據(jù)庫連接。

oracleparameter

oraclecommand 的參數(shù),也可能是它到 datacolumn 的映射。

oracleparametercollection

oracleparameter 對象的集合。

oracletype

oracle 數(shù)據(jù)類型和結(jié)構(gòu)的枚舉。

  執(zhí)行存儲過程

  執(zhí)行 oracle 存儲過程與執(zhí)行 sql server 存儲過程類似。下面的步驟說明了如何執(zhí)行 oracle 存儲過程和檢索它返回的結(jié)果。

  1.在 hr 架構(gòu)中創(chuàng)建一個名為 count_job_history 的存儲過程,以計算 job_history 表中的記錄數(shù)。

create or new procedure count_job_history
(
    reccount out number
)
is
begin
    select count(*) into reccount
    from job_history;
end count_job_history;

  hr 架構(gòu)是默認(rèn) oracle 安裝中包含的一個示例。
 
  2.將 system.data.oracleclient.dll(用于 oracle 的 microsoft .net 框架數(shù)據(jù)提供程序)的引用添加到項目中。
 
  3. 使用 using 指令導(dǎo)入 oracleclient 類中的類型。

using system.data.oracleclient;

  4.創(chuàng)建一個 oracleconnection 對象。

oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

  用您的值替換 oracle 數(shù)據(jù)庫的名稱、用戶名和密碼。
 
  5. 創(chuàng)建一個 oraclecommand 對象。將其 connection 屬性設(shè)置為第 4 步中創(chuàng)建的連接。將其 commandtext 設(shè)置為存儲過程的名稱,并將其 commandtext 屬性設(shè)置為 commandtype.storedprocedure。當(dāng)您調(diào)用第 8 步中介紹的一個 execute() 方法時,該命令對象將執(zhí)行指定的存儲過程。

oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "count_job_history";
cmd.commandtype = commandtype.storedprocedure;

  如果您的存儲過程名稱含有特殊字符,您就必須使用轉(zhuǎn)義序列。您可以通過重置 commandtext 屬性來重用現(xiàn)有的 oraclecommand 對象。
 
  6. 創(chuàng)建輸入、輸出和返回值的 oracleparameter 對象,并將其添加到 oraclecommand 對象的參數(shù)集合中。

cmd.parameters.add("reccount", oracletype.number).direction =
    parameterdirection.output;

  該行代碼是以下兩行代碼的簡寫形式:

cmd.parameters.add("reccount", oracletype.number);
cmd.parameters["reccount"].direction = parameterdirection.output;

  7. 如果您要檢索結(jié)果集,請創(chuàng)建 dataset、datatable 或 datareader。在本示例中,我們只是獲取第 6 步中創(chuàng)建的輸出參數(shù)中的計數(shù)。

  8. 使用 oraclecommand 對象的一個 execute 方法打開連接并執(zhí)行存儲過程,如下所示:

方法說明

executereader

通過執(zhí)行能夠返回結(jié)果集的存儲過程生成 oracledatareader

executenonquery

執(zhí)行不返回結(jié)果集的查詢或過程,返回受影響的行數(shù)。

executeoraclenonquery

執(zhí)行查詢,返回受影響的行數(shù)。

該方法還使用 oraclestring 參數(shù)來返回 updateinsertdelete 查詢所修改的最后一行的行 id。

executescalar

執(zhí)行一個查詢或過程,并且返回查詢或過程的返回值,或者將結(jié)果集第一行第一列的值作為 .net 框架數(shù)據(jù)類型返回。

executeoraclescalar

執(zhí)行一個查詢或過程,并且返回查詢或過程的返回值,或者將結(jié)果集第一行第一列的值作為 oracletype 數(shù)據(jù)類型返回。

  使用完連接后,不要忘記將其關(guān)閉。

conn.open();
cmd.executenonquery();
conn.close();

  如果您要使用 dataadapter 來填充 datatable 或 dataset,可以依靠 dataadapter 來打開和關(guān)閉連接。
 
  9. 處理結(jié)果。在我們的示例中,可在顯示到控制臺的輸出參數(shù)中得到記錄數(shù):

console.writeline(cmd.parameters["reccount"].value);

  下面是在本示例中開發(fā)的用于執(zhí)行存儲過程和檢索結(jié)果的代碼:

oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "count_job_history";
cmd.commandtype = commandtype.storedprocedure;
cmd.parameters.add("reccount", oracletype.number).direction =
    parameterdirection.output;

conn.open();
cmd.executenonquery();
conn.close();

console.writeline(cmd.parameters["reccount"].value);

  不返回數(shù)據(jù)的存儲過程

  oraclecommand 類的 executeoraclenonquery() 方法用于執(zhí)行不返回任何行的 sql 語句或存儲過程。該方法返回一個 int 值,表示受 update、insert 和 delete 命令影響的行數(shù);如果沒有任何行受到影響,則返回 -1。如果您所執(zhí)行的 insert、delete 或 update 語句恰好影響一行,則該方法具有單個參數(shù) oraclestring out rowid,該參數(shù)唯一標(biāo)識 oracle 數(shù)據(jù)庫中受影響的行。可以使用該值來優(yōu)化后續(xù)相關(guān)查詢。

  還可以使用 oraclecommand 類的 executenonquery() 方法來執(zhí)行不返回數(shù)據(jù)的存儲過程,但您將無法獲得上面介紹的唯一行標(biāo)識符。

  盡管上述命令都不會返回任何數(shù)據(jù),但映射到參數(shù)的輸出參數(shù)和返回值仍然使用數(shù)據(jù)進(jìn)行填充。這使您可以使用上述任一命令從存儲過程返回一個或多個標(biāo)量值。

  以下 oracle 存儲過程刪除了由單個輸入?yún)?shù)指定的員工的所有工作經(jīng)歷,并且不返回任何數(shù)據(jù)。

create or new procedure delete_job_history
(
    p_employee_id number
)
is
begin
    delete from job_history
    where employee_id = p_employee_id;
end delete_job_history;

  以下代碼運行了該存儲過程。

// create the connection
oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

// create the command for the stored procedure
oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "count_job_history";
cmd.commandtype = commandtype.storedprocedure;

// add the parameter specifying the employee for whom to delete records
cmd.parameters.add("p_employee_id", oracletype.number).value = 102;

oraclestring rowid;
// execute the stored procedure
conn.open();
int rowsaffected = cmd.executenonquery();
conn.close();

console.writeline("rows affected: " + rowsaffected);

  如果您尚未修改默認(rèn)的 hr 安裝,則 job_history 表中員工 102 的記錄被刪除,并且向控制臺輸出以下內(nèi)容:

rows affected: 1

  訪問返回值

  return 語句立即將控制從存儲過程返回到調(diào)用程序。oracle 存儲過程中的 return 語句無法像在 t-sql 中那樣返回值。

  oracle 函數(shù)是計算并返回單個值的子程序。它們的結(jié)構(gòu)類似于存儲過程,不同之處在于它們總是具有必須返回值的 return 子句。

  下面是一個返回指定員工的電子郵件的函數(shù):

create or new function get_employee_email (
    p_employee_id number
)
return varchar2
is p_email varchar2(25);
begin
    select email into p_email from employees
    where employee_id = p_employee_id;
   
    return p_email;
end get_employee_email;

  執(zhí)行函數(shù)的方式與執(zhí)行存儲過程的方式相同。可使用 parameterdirection.returnvalue 參數(shù)獲得由函數(shù)返回的結(jié)果。以下代碼顯示了使用方法:

// create the connection
oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

// create the command for the function
oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "get_employee_email";
cmd.commandtype = commandtype.storedprocedure;

// add the parameters, including the return parameter to retrieve
// the return value
cmd.parameters.add("p_employee_id", oracletype.number).value = 101;
cmd.parameters.add("p_email", oracletype.varchar, 25).direction =
    parameterdirection.returnvalue;

// execute the function
conn.open();
cmd.executenonquery();
conn.close();

// output the result
console.writeline("email address is: " + cmd.parameters["p_email"].value);

  控制臺輸出顯示了員工 101 的電子郵件地址。

email address is: nkochhar

  結(jié)果集與 ref cursor

  可使用 ref cursor 數(shù)據(jù)類型來處理 oracle 結(jié)果集。ref cursor 是一個指向 pl/sql 查詢所返回的結(jié)果集的指針。與普通的游標(biāo)不同,ref cursor 是一個變量,它是對游標(biāo)的引用,可以在執(zhí)行時將其設(shè)置為指向不同的結(jié)果集。使用 ref cursor 輸出參數(shù)可以將 oracle 結(jié)構(gòu)化程序的結(jié)果集傳遞回調(diào)用應(yīng)用程序。通過在調(diào)用應(yīng)用程序中定義 oracletype.cursor 數(shù)據(jù)類型的輸出參數(shù),可以訪問 ref cursor 所指向的結(jié)果集。在使用 ref cursor 的過程中,oracleconnection 必須保持打開狀態(tài)。

  包

  pl/sql 和 t-sql 中的存儲過程之間的一個重大差異是 pl/sql 所使用的 oracle 包 結(jié)構(gòu)。在 t-sql 中沒有等效元素。包是在邏輯上相關(guān)的編程塊(如存儲過程和函數(shù))的容器。它包含兩個部分:

  • 規(guī)范:定義包的名稱,并為包中的每個存儲過程或函數(shù)提供方法簽名(原型)。規(guī)范頭還定義所有全局聲明。規(guī)范的樣式類似于 c 或 c++ 頭文件。
 
  • 正文:包含包頭中定義的存儲過程和函數(shù)的代碼。

  每個存儲過程或函數(shù)的參數(shù)都出現(xiàn)在括號內(nèi),并且用逗號分隔。每個參數(shù)還根據(jù)需要用以下三個標(biāo)識符中的一個進(jìn)行標(biāo)記:

  • in:該值從調(diào)用應(yīng)用程序傳遞到 pl/sql 塊。如果未指定標(biāo)識符,則 in 為默認(rèn)傳遞方向。
 
  • out:該值由存儲過程生成,并傳遞回調(diào)用應(yīng)用程序。
 
  • inout:該值被傳遞到 pl/sql 塊,可能在該塊內(nèi)部進(jìn)行修改,然后返回到調(diào)用應(yīng)用程序。

  每個參數(shù)也都被標(biāo)記以指示數(shù)據(jù)類型。

  以下包規(guī)范定義了四個過程,它們在 hr 架構(gòu)的 locations 表中創(chuàng)建、檢索、更新和刪除數(shù)據(jù)。

create or new package crud_locations as
type t_cursor is ref cursor;
procedure getlocations (cur_locations out t_cursor);
procedure updatelocations (p_location_id in number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char);
procedure deletelocations (p_location_id in number);
procedure insertlocations (p_location_id out number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char);
end crud_locations;

  以下代碼摘自上述包規(guī)范的包正文,說明了 getlocations 包中的第一個過程的實現(xiàn)細(xì)節(jié):

create or new package body crud_locations as
procedure getlocations (cur_locations out t_cursor)
is
begin
    open cur_locations for
    select * from locations;
end getlocations;

-- implementation of other procedures ommitted.

end crud_locations;

  使用 datareader

  可以通過調(diào)用 oraclecommand 對象的 executereader() 方法來創(chuàng)建 oracledatareader。本節(jié)說明如何使用 datareader 來訪問由存儲過程 select_job_history 返回的結(jié)果集。以下為包規(guī)范:

create or new package select_job_history as
type t_cursor is ref cursor;
procedure getjobhistorybyemployeeid
(
    p_employee_id in number,
    cur_jobhistory out t_cursor
);
end select_job_history;

  包正文定義了一個過程,該過程檢索指定員工的工作經(jīng)歷的結(jié)果集,并將其作為 ref cursor 輸出參數(shù)返回:

create or new package body select_job_history as
procedure getjobhistorybyemployeeid
(
    p_employee_id in number,
    cur_jobhistory out t_cursor
)
is
begin
    open cur_jobhistory for
    select * from job_history
        where employee_id = p_employee_id;

end getjobhistorybyemployeeid;
end select_job_history;

  以下代碼執(zhí)行該過程,根據(jù)結(jié)果集創(chuàng)建 datareader,并將 datareader 的內(nèi)容輸出到控制臺。

// create connection
oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

// create the command for the stored procedure
oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "select_job_history.getjobhistorybyemployeeid";
cmd.commandtype = commandtype.storedprocedure;

// add the parameters for the stored procedure including the ref cursor
// to retrieve the result set
cmd.parameters.add("p_employee_id", oracletype.number).value = 101;
cmd.parameters.add("cur_jobhistory", oracletype.cursor).direction =
    parameterdirection.output;

// open the connection and create the datareader
conn.open();
oracledatareader dr = cmd.executereader();

// output the results and close the connection.
while(dr.read())
{
    for(int i = 0; i < dr.fieldcount; i++)
        console.write(dr[i].tostring() + ";");
    console.writeline();
}
conn.close();

  對于 hr 架構(gòu)的默認(rèn)安裝,控制臺輸出顯示了員工 101 的兩個記錄中每個記錄的字段(用分號分隔):

101;9/21/1989 12:00:00 am;10/27/1993 12:00:00 am;ac_account;110;
101;10/28/1993 12:00:00 am;3/15/1997 12:00:00 am;ac_mgr;110;

  上述代碼顯示,包中的過程是使用包名稱 (elect_job_history) 和過程的名稱(在此情況下為 getjobhistorybyemployeeid)指定的,二者之間用句點分隔。

  代碼還說明了如何定義結(jié)果集的 ref cursor 參數(shù)。請注意,數(shù)據(jù)類型為 oracletype.cursor,方向為 parameterdirection.output。

  還請注意,在訪問 ref cursor 中的結(jié)果集的整個過程中,連接都保持打開狀態(tài)。

  如果包返回多個游標(biāo),則 datareader 會按照您向參數(shù)集合中添加它們的順序來訪問這些游標(biāo),而不是按照它們在過程中出現(xiàn)的順序來訪問。可使用 datareader 的 nextresult() 方法前進(jìn)到下一個游標(biāo)。

  返回單個值的存儲過程

  oraclecommand 類的 executeoraclescalar() 方法用于執(zhí)行將單個值作為 oracletype 數(shù)據(jù)類型返回的 sql 語句或存儲過程。如果命令返回一個結(jié)果集,則該方法會返回第一行第一列的值。如果返回了 ref cursor,而不是返回了 ref cursor 所指向的第一行第一列的值,則該方法會返回一個空引用。oraclecommand 類的 executescalar() 方法類似于 executeoraclescalar() 方法,只不過它將值作為 .net 框架數(shù)據(jù)類型返回。

  盡管如此,在使用 oracle 存儲過程時,這兩個方法都沒有用。oracle 存儲過程不能將值作為 return 語句的一部分返回,而只能將其作為 out 參數(shù)返回。有關(guān)信息,請參閱不返回數(shù)據(jù)的存儲過程一節(jié)。同時,除了通過 ref cursor 輸出參數(shù)以外,您不能返回結(jié)果集。下一節(jié)將對此進(jìn)行討論。

  您只能使用 return 參數(shù)檢索 oracle 函數(shù)的返回值(如上一節(jié)所述),而不能使用 executescalar 方法之一進(jìn)行檢索。

  序列

  oracle 使用序列 來生成唯一編號,而不是使用 sql server 所用的數(shù)據(jù)類型 uniqueidentifier。無論是哪種情況,主要用途都是為主鍵列生成一系列唯一編號。與 uniqueidentifier 數(shù)據(jù)類型不同,序列是與將其用于主鍵值的一個或多個表無關(guān)的數(shù)據(jù)庫對象。

  oracle 序列是原子對象,并且是一致的。也就是說,一旦您訪問一個序列號,oracle 將在處理下一個請求之前自動遞增下一個編號,從而確保不會出現(xiàn)重復(fù)值。

  可以使用 create sequence 命令創(chuàng)建 oracle 序列。該命令所帶參數(shù)包括增量、起始值、最大值、循環(huán)和緩存。可使用 nextval 和 currval 關(guān)鍵字訪問序列值。nextval 返回序列中的下一個編號,而 currval 提供對當(dāng)前值的訪問。hr 架構(gòu)中的序列 locations_seq 按如下方式定義:

create sequence locations_seq
    increment by 100
    start with 1
    maxvalue 9900
    minvalue 1
    nocycle
    nocache
    noorder

  大多數(shù)序列代碼是不言自明的。nocycle 表示序列在達(dá)到最小值或最大值后將不再生成其他值。nocache 表示序列值在被請求之前不會進(jìn)行分配;可使用預(yù)分配機(jī)制來改善性能。noorder 表示在生成編號時,不能保證按照請求編號的順序返回這些編號。

  下面的代碼顯示了一個存儲過程,該過程請求一個序列值,在向 locations 表中插入記錄時使用它設(shè)置主鍵值,然后在 out 參數(shù)中返回該主鍵值。

create or new procedure add_location (
    p_location_id out number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char
)
as
begin
    insert into locations (
        location_id,
        street_address,
        postal_code,
        city,
        state_province,
        country_id)
    values (
        locations_seq.nextval,
        p_street_address,
        p_postal_code,
        p_city,
        p_state_province,
        p_country_id
    );
   
    select locations_seq.currval into p_location_id from dual;
end add_location;

  下面的代碼調(diào)用該存儲過程,以插入一個記錄并檢索返回的序列值。

// create the connection
oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

// create the command for the stored procedure
oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "add_location";
cmd.commandtype = commandtype.storedprocedure;

// add the parameters for the stored procedure including the location_id
// sequence value that is returned in the output parameter p_location_id
cmd.parameters.add("p_location_id", oracletype.number).direction =
    parameterdirection.output;
cmd.parameters.add("p_street_address", oracletype.varchar).value =
    "123 any street";
cmd.parameters.add("p_postal_code", oracletype.varchar).value = "33040";
cmd.parameters.add("p_city", oracletype.varchar).value = "key west";
cmd.parameters.add("p_state_province", oracletype.varchar).value = "fl";
cmd.parameters.add("p_country_id", oracletype.varchar).value = "us";

// execute the command to add the records     
oraclestring rowid;
conn.open();
int rowsaffected = cmd.executeoraclenonquery(out rowid);
conn.close();

// output the results
console.writeline("rows affected: " + rowsaffected);
console.writeline("location id: " +
    cmd.parameters["p_location_id"].value);

  控制臺顯示一個記錄被插入到該表中,同時還插入了該序列生成的主鍵值。

rows affected: 1
location id: 3300

  使用 dataadapter 填充數(shù)據(jù)集

  可使用 ref cursor 通過 dataadapter 來填充 dataset。下面的代碼利用了使用 datareader 一節(jié)中定義的存儲過程 getjobhistorybyemployeeid,并用它在 ref cursor 輸出參數(shù)中返回的結(jié)果集來填充 dataset。

以下是使用 dataadapter 填充 dataset 的代碼:

// create the connection
oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

// create the command for the stored procedure
oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "select_job_history.getjobhistorybyemployeeid";
cmd.commandtype = commandtype.storedprocedure;

// add the parameters for the stored procedure including the ref cursor
// to retrieve the result set
cmd.parameters.add("p_employee_id", oracletype.number).value = 101;
cmd.parameters.add("cur_jobhistory", oracletype.cursor).direction =
    parameterdirection.output;

// createt the dataadapter from the command and use it to fill the
// dataset
oracledataadapter da = new oracledataadapter(cmd);
dataset ds = new dataset();
da.fill(ds);

// output the results.
console.writeline(ds.tables[0].rows.count);

  對于 hr 架構(gòu)的默認(rèn)安裝,輸出表明員工 101 有兩個 job_history 記錄。

  使用 dataadapter 更新 oracle

  當(dāng)您使用 ref cursor 參數(shù)填充 dataset 時,不能簡單地使用 oracledataadapter 的 update() 方法。這是因為在執(zhí)行存儲過程時,oracle 不能提供確定表名和列名所需的信息。要使用 dataadapter 的 update() 方法,您必須創(chuàng)建在基礎(chǔ)表中更新、插入和刪除記錄的過程。該方法類似于在 sql server 中使用的方法。

  本節(jié)說明如何生成一個可以處理所需的創(chuàng)建、檢索、更新和刪除操作的包,以便能夠從 oracle 數(shù)據(jù)庫中檢索 location 數(shù)據(jù),也能夠?qū)?dataset 數(shù)據(jù)所做的不連續(xù)更改重新更新到 oracle 數(shù)據(jù)庫。包頭如下所示:

create or new package crud_locations as
type t_cursor is ref cursor;
procedure getlocations (cur_locations out t_cursor);
procedure updatelocations (
    p_location_id in number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char);
procedure deletelocations (p_location_id in number);
procedure insertlocations (
    p_location_id out number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char);
end crud_locations;

  包正文如下所示:

create or new package body crud_locations as
-- retrieve all location records
procedure getlocations (cur_locations out t_cursor)
is
begin
    open cur_locations for
    select * from locations;
end getlocations;

-- update a location record
procedure updatelocations (
    p_location_id in number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char)
is
begin
    update locations
    set
        street_address = p_street_address,
        postal_code = p_postal_code,
        city = p_city,
        state_province = p_state_province,
        country_id = p_country_id
    where
        location_id = p_location_id;       
end updatelocations;

-- delete a location record
procedure deletelocations (p_location_id in number)
is
begin
     delete from locations
     where location_id = p_location_id;
end deletelocations;

-- insert a location record
procedure insertlocations
(
    p_location_id out number,
    p_street_address in varchar2,
    p_postal_code in varchar2,
    p_city in varchar2,
    p_state_province in varchar2,
    p_country_id in char
)
as
begin
    insert into locations (
        location_id,
        street_address,
        postal_code,
        city,
        state_province,
        country_id)
    values (
        locations_seq.nextval,
        p_street_address,
        p_postal_code,
        p_city,
        p_state_province,
        p_country_id
    );
   
    select locations_seq.currval into p_location_id from dual;
end insertlocations;
end crud_locations;

  下面的代碼定義了一個 dataadapter,從而使用上述包中定義的過程來創(chuàng)建、檢索、更新和刪除支持 dataadapter 的數(shù)據(jù)。dataadapter 既可用來將數(shù)據(jù)檢索到 dataset 中,也可用來將對 dataset 所做的更改更新到 oracle 數(shù)據(jù)庫中。

// define the connection string
string connstring = "data source=oracledb;user id=userid;password=password;";

// create the data adapter
oracledataadapter da = new oracledataadapter();

// define the select command for the data adapter
oraclecommand selectcommand =
    new oraclecommand("crud_locations.getlocations",
    new oracleconnection(connstring));
selectcommand.commandtype = commandtype.storedprocedure;
selectcommand.parameters.add("cur_locations",
    oracletype.cursor).direction = parameterdirection.output;
da.selectcommand = selectcommand;

// define the udpate command for the data adapter
oraclecommand updatecommand =
    new oraclecommand("crud_locations.updatelocations",
    new oracleconnection(connstring));
updatecommand.commandtype = commandtype.storedprocedure;
updatecommand.parameters.add("p_location_id", oracletype.number, 4,
    "location_id");
updatecommand.parameters.add("p_street_address", oracletype.varchar, 40,
    "street_address");
updatecommand.parameters.add("p_postal_code", oracletype.varchar, 12,
    "postal_code");
updatecommand.parameters.add("p_city", oracletype.varchar, 30, "city");
updatecommand.parameters.add("p_state_province", oracletype.varchar, 25,
    "state_province");
updatecommand.parameters.add("p_country_id", oracletype.char, 2,
    "country_id");
da.updatecommand = updatecommand;

// define the delete command for the data adapter
oraclecommand deletecommand =
    new oraclecommand("crud_locations.deletelocations",
    new oracleconnection(connstring));
deletecommand.commandtype = commandtype.storedprocedure;
deletecommand.parameters.add("p_location_id", oracletype.number, 4,
    "location_id");
da.deletecommand = deletecommand;

oraclecommand insertcommand =
    new oraclecommand("crud_locations.insertlocations",
    new oracleconnection(connstring));
insertcommand.commandtype = commandtype.storedprocedure;
insertcommand.parameters.add("p_location_id", oracletype.number, 4,
    "location_id");
insertcommand.parameters.add("p_street_address", oracletype.varchar, 40,
    "street_address");
insertcommand.parameters.add("p_postal_code", oracletype.varchar, 12,
    "postal_code");
insertcommand.parameters.add("p_city", oracletype.varchar, 30, "city");
insertcommand.parameters.add("p_state_province", oracletype.varchar, 25,
    "state_province");
insertcommand.parameters.add("p_country_id", oracletype.char, 2,
    "country_id");
da.insertcommand = insertcommand;

// define a datatable and fill it using the data adapter
datatable dt = new datatable();
da.fill(dt);

// ... do work that adds, edits, updates, or deletes records in the table

// call the update() method of the data adapter to update the oracle
// database with changes made to the data
da.update(dt);

  使用多個結(jié)果集

  oracle 不支持批量查詢,因此無法從一個命令返回多個結(jié)果集。使用存儲過程時,返回多個結(jié)果集類似于返回單個結(jié)果集;必須使用 ref cursor 輸出參數(shù)。要返回多個結(jié)果集,請使用多個 ref cursor 輸出參數(shù)。

  以下是返回兩個結(jié)果集(全部 employees 和 jobs 記錄)的包規(guī)范:

create or new package select_employees_jobs as
type t_cursor is ref cursor;
procedure getemployeesandjobs (
    cur_employees out t_cursor,   
    cur_jobs out t_cursor
);
end select_employees_jobs;

  包正文如下所示:

create or new package body select_employees_jobs as
procedure getemployeesandjobs
(
    cur_employees out t_cursor,
    cur_jobs out t_cursor
)
is
begin
    -- return all employees records
    open cur_employees for
    select * from employees;

    -- return all jobs records
    open cur_jobs for
    select * from jobs;
end getemployeesandjobs;
end select_employees_jobs;

  以下代碼顯示了如何使用從上述包中返回的兩個結(jié)果集來填充 dataset 中的兩個相關(guān)表:

// create the connection
oracleconnection conn = new oracleconnection("data source=oracledb;
    user id=userid;password=password;");

// define the command for the stored procedure
oraclecommand cmd = new oraclecommand();
cmd.connection = conn;
cmd.commandtext = "select_employees_jobs.getemployeesandjobs";

// add the parameters including the two ref cursor types to retrieve
// the two result sets
cmd.parameters.add("cur_employees", oracletype.cursor).direction =
    parameterdirection.output;
cmd.parameters.add("cur_jobs", oracletype.cursor).direction =
    parameterdirection.output;
cmd.commandtype = commandtype.storedprocedure;

// create the dataadapter and map tables
oracledataadapter da = new oracledataadapter(cmd);
da.tablemappings.add("table", "employees");
da.tablemappings.add("table1", "jobs");

// create and fill the dataset
dataset ds = new dataset();
da.fill(ds);

// create a relation
ds.relations.add("employees_jobs_relation",
   ds.tables["jobs"].columns["job_id"],
   ds.tables["employees"].columns["job_id"]);

// output the second employee (zero-based array) and job title
// based on the relation
console.writeline("employee id: " +
    ds.tables["employees"].rows[1]["employee_id"] +
    "; job title: " +
    ds.tables["employees"].rows[1].getparentrow(
    "employees_jobs_relation")["job_title"]);

  控制臺輸出顯示了第二個員工的職務(wù):

employee id: 101; job title: administration vice president

  小結(jié)

  通過 oracle .net 數(shù)據(jù)提供程序,可以方便地執(zhí)行存儲過程以及訪問返回值(無論返回值是一個還是多個標(biāo)量值或結(jié)果集)。可以將 oracle 過程與 oracledataadapter 結(jié)合使用,從而填充 dataset、處理不連續(xù)的數(shù)據(jù)以及以后將更改更新到 oracle 數(shù)據(jù)庫。

  oracle 過程與 microsoft sql server 存儲過程之間的主要區(qū)別是:oracle 過程必須將值作為輸出參數(shù)返回,并且必須使用輸出參數(shù)將結(jié)果集作為 ref cursor 對象返回給調(diào)用程序。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 宜兴市| 永昌县| 桂阳县| 定襄县| 曲麻莱县| 乐都县| 望江县| 会理县| 延安市| 鹿邑县| 遵义市| 博罗县| 习水县| 富阳市| 松阳县| 曲水县| 唐海县| 五原县| 包头市| 桂阳县| 个旧市| 乌恰县| 山东省| 崇礼县| 青阳县| 连州市| 隆尧县| 张家界市| 鹤岗市| 宁阳县| 杭州市| 肇源县| 左权县| 余庆县| 南京市| 儋州市| 正定县| 铜鼓县| 永春县| 罗江县| 武功县|