使用 WCF 服務模型叫用 Oracle 資料庫中的函式和程式
Microsoft BizTalk Adapter for Oracle Database 會以作業的形式呈現程式、函式和套件。 在 WCF 服務模型中,這些作業會以 WCF 用戶端上的方法表示。 WCF 服務模型和 Oracle 資料庫配接器:
支援函式。 Oracle 函式的 RETURN 值會呈現為 WCF 用戶端方法的傳回值。 Oracle 參數會以參數的形式呈現 (,其方向如下所定義,) WCF 用戶端方法。
支援程式。 Oracle 程式的第一個 OUT 參數會呈現為 WCF 用戶端方法的傳回值。 所有其他 Oracle 參數都會以參數的形式呈現 (,其方向如下所定義,) WCF 用戶端方法。
支援 Oracle 套件。 作業的名稱及其參數類型的命名空間會以封裝名稱限定。
支援多載函式和程式。
支援程式和函式的基本 Oracle 資料類型 IN、OUT 和 IN OUT 參數。 OUT 參數會以 WCF 用戶端方法上的 out 參數呈現,而 IN OUT 參數則會以 ref 參數呈現。
支援程式和函式的 IN、OUT 和 IN OUT REF CURSOR 參數,以及函式 RETURN 值。 如需詳細資訊,請參閱 使用 WCF 服務模型在 Oracle 資料庫中使用 REF CURSORS 執行作業。
支援程式和函式的 IN、OUT 和 IN OUT RECORD 類型參數,以及函式 RETURN 值。 如需詳細資訊,請參閱 使用 WCF 服務模型在 Oracle 資料庫中使用 RECORD 類型執行作業。
關於本主題中使用的範例
本主題中的範例會使用 /SCOTT/Package/ACCOUNT_PKG/GET_ACCOUNT 多載程式。 此程式會根據帳戶識別碼或帳戶名稱,從 SCOTT/ACCOUNT 資料表讀取記錄。 用來產生此程式和資料表的腳本會隨附 SDK 範例。 如需 SDK 範例的詳細資訊,請參閱 SDK 中的範例。
WCF 用戶端類別
下表顯示 WCF 用戶端的名稱,以及針對 Oracle 資料庫配接器介面的程式、函式和封裝所產生的方法。 除非函式或程式多載,否則單一 WCF 用戶端會用來叫用架構中的所有函式、架構中的所有程式,或封裝中的所有函式和程式。
Oracle Artifact | WCF 用戶端作業名稱 | 範例 |
---|---|---|
程序 | [SCHEMA]ProcedureClient。[PROC_NAME] | SCOTTProcedureClient.MYPROC |
函式 | [SCHEMA]FunctionClient。[FUNC_NAME] | SCOTTProcedureClient.MYFUNC |
套件 (程式或函式) | [SCHEMA]Package[PACKAGE_NAME]Client。[PROC_NAME或FUNC_NAME] | SCOTTPackageMYPACKAGEClient.MYPROC |
[SCHEMA] = Oracle 成品的集合;例如,SCOTT。
[PROC_NAME] = Oracle 程式的名稱;例如 MYPROC。
[FUNC_NAME] = Oracle 函式的名稱;例如,MYFUNC。
[PACKAGE_NAME] = Oracle 套件的名稱。
Oracle 資料庫配接器代表 Oracle RECORD 類型參數和傳回值,以及 REF CURSOR 參數所傳回的結果集,做為包含 Oracle 記錄之資料列資料 (或欄位) 的複雜 XML 類型。 在 WCF 服務模型中,每個 XML 類型都會以 .NET 類別表示;類別的屬性代表 RECORD 類型或 REF CURSOR 結果集的欄位。 Oracle RECORD 類型一律以強型別 .NET 類別表示。 不過,REF CURSOR 結果集可以表示為強型別或弱型別記錄,根據 REF CURSOR 本身是否宣告為強型別或弱型別。 代表 REF CURSOR 或 RECORD 類型參數的類別 (或傳回值,) 是根據程式、函式或封裝,在唯一命名空間中產生。 下表顯示這些命名空間。
Oracle Artifact | 命名空間 | 範例 |
---|---|---|
程序 | [BASE_NS]。 [SCHEMA]。程式。[PROC_NAME] | microsoft.lobservices.oracledb._2007._03.SCOTT。Procedure.MYPROC |
函式 | [BASE_NS]。 [SCHEMA]。功能。[FUNC_NAME] | microsoft.lobservices.oracledb._2007._03.SCOTT。Function.MYFUNC |
套件 (程式) | [BASE_NS]。 [SCHEMA]。包。[PACKAGE_NAME]。[PROC_NAME] | microsoft.lobservices.oracledb._2007._03.SCOTT。Package.MYPACKAGE.MYPROC |
套件 (函式) | [BASE_NS]。 [SCHEMA]。包。[PACKAGE_NAME]。[FUNC_NAME] | microsoft.lobservices.oracledb._2007._03.SCOTT。Package.MYPACKAGE.MYFUNC |
泛型記錄集 (弱型別) | [BASE_NS] | microsoft.lobservices.oracledb._2007._03 |
[BASE_NS] = 基底配接器命名空間;microsoft.lobservices.oracledb._2007._03。
[SCHEMA] = Oracle 成品的集合;例如,SCOTT。
[PROC_NAME] = Oracle 程式的名稱;例如;MYPROC。
[FUNC_NAME] = Oracle 函式的名稱;例如 MYFUNC。
[PACKAGE_NAME] = Oracle 套件的名稱。
如需這些命名空間如何用於 RECORD 參數的資訊,請參閱 使用 WCF 服務模型在 Oracle 資料庫中使用 RECORD 類型執行作業。 如需這些命名空間如何用於 REF CURSOR 參數的資訊,請參閱 使用 WCF 服務模型在 Oracle 資料庫中使用 REF CURSORS 執行作業。
一般而言,Oracle 參數和傳回值會對應如下 WCF 用戶端方法:
Oracle IN 參數會對應至 .NET (輸入) 參數。
Oracle OUT 參數會對應至 .NET out 參數。
Oracle IN OUT 參數會對應至 .NET ref 參數。
函式 RETURN 值會對應至方法傳回值。
不過,有兩個重要的例外狀況存在:
Oracle IN OUT REF CURSOR 參數會分割成輸入字串,而輸出 (輸出) 記錄集。 這是因為 Oracle 資料庫配接器代表 IN REF CUSROR 參數做為字串,而 OUT REF CURSOR 參數做為複雜類型, (記錄集) ,這些參數無法合併成單一參數。
Oracle 程式中的第一個 OUT 參數會對應至 WCF 用戶端方法的傳回值。 這是標準 WCF 行為。
下列範例顯示簡單 Oracle 程式的一部分 (載入 SCOTT 架構) ,以及產生來叫用它之 WCF 用戶端方法的簽章。 Oracle 程式有三個 IN 參數、三個 IN OUT 參數,以及三個 OUT 參數;不過,WCF 用戶端方法不會對應第一個 OUT 參數的參數。 而是對應至方法傳回值。
CREATE or REPLACE PROCEDURE Sample_Procedure
(
INNUMBER IN NUMBER,
INVARCHAR IN VARCHAR2,
INDATE IN DATE,
INOUTNUMBER IN OUT NUMBER,
INOUTVARCHAR IN OUT VARCHAR,
INOUTDATE IN OUT DATE,
OUTNUMBER OUT NUMBER,
OUTVARCHAR OUT VARCHAR2,
OUTDATE OUT DATE
) AS
BEGIN
...
END;
/
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class SCOTTProcedureClient : System.ServiceModel.ClientBase<SCOTTProcedure>, SCOTTProcedure {
public System.Nullable<decimal> SAMPLE_PROCEDURE
(
System.Nullable<decimal> INNUMBER,
string INVARCHAR,
System.Nullable\<System.DateTime\> INDATE,
ref System.Nullable<decimal> INOUTNUMBER,
ref string INOUTVARCHAR,
ref System.Nullable\<System.DateTime\> INOUTDATE,
out string OUTVARCHAR,
out System.Nullable\<System.DateTime\> OUTDATE
);
}
支援多載程式、函式和套件
Oracle 資料庫配接器支援多載程式、函式和套件,方法是將唯一字串附加至節點識別碼,以及它針對每個多載成品呈現的命名空間。 此字串是第一個多載的 「多載1」、下一個多載的 「overload2」 等等。
在 WCF 服務模型中,每個多載程式或函式都是由唯一的 WCF 用戶端表示。 這與非多載案例不同,其中 SCHEMA 中的所有函式、SCHEMA 中的所有程式,或 PACKAGE 中的所有程式和函式都會由相同的 WCF 用戶端叫用。 下表顯示針對多載程式、函式和封裝產生的 WCF 用戶端名稱和方法。
Oracle Artifact | WCF 用戶端名稱 | 範例 |
---|---|---|
多載套件 (程式) | [SCHEMA]Package[PACKAGE_NAME][PROC_NAME] ][OVERLOAD_ID]Client。[PROC_NAME] | SCOTTPackageMYPACKAGEMYPROCoverload1Client.MYPROC |
多載套件 (函式) | [SCHEMA]Package[PACKAGE_NAME][FUNC_NAME] ][OVERLOAD_ID]Client。[FUNC_NAME] | SCOTTPackageMYPACKAGEMYFUNCoverload1Client.MYFUNC |
[SCHEMA] = Oracle 成品的集合;例如,SCOTT。
[PROC_NAME] = Oracle 程式的名稱;例如;MYPROC。
[FUNC_NAME] = Oracle 函式的名稱;例如 MYFUNC。
[PACKAGE_NAME] = Oracle 套件的名稱。
[OVERLOAD_ID] = 識別多載成品的唯一字串;「overload1」、「overload2」 等等。
下表顯示針對多載程式、函式和封裝所產生的命名空間。
Oracle Artifact | 命名空間 | 範例 |
---|---|---|
套件 (程式) | [BASE_NS]。 [SCHEMA]。包。[PACKAGE_NAME]。[PROC_NAME][OVERLOAD_ID] | microsoft.lobservices.oracledb._2007._03.SCOTT。Package.MYPACKAGE.MYPROC.overload1 |
套件 (函式) | [BASE_NS]。 [SCHEMA]。包。[PACKAGE_NAME]。[FUNC_NAME]。[OVERLOAD_ID] | microsoft.lobservices.oracledb._2007._03.SCOTT。Package.MYPACKAGE.MYFUNC.overload1 |
泛型記錄集 (弱型別) | [BASE_NS] | microsoft.lobservices.oracledb._2007._03 |
[BASE_NS] = 基底配接器命名空間;microsoft.lobservices.oracledb._2007._03。
[SCHEMA] = Oracle 成品的集合;例如,SCOTT。
[PROC_NAME] = Oracle 程式的名稱;例如;MYPROC。
[FUNC_NAME] = Oracle 函式的名稱;例如 MYFUNC。
[PACKAGE_NAME] = Oracle 套件的名稱。
[OVERLOAD_ID] = 識別多載成品的唯一字串;「overload1」、「overload2」 等等。 字串中的數值是 Oracle 資料庫所維護成品的多載識別碼。
下列範例顯示針對ACCOUNT_PKG套件中多載GET_ACCOUNT程式所產生的 WCF 用戶端和方法簽章。 (包含 Oracle 宣告。) 本範例示範如何為每個多載產生唯一的 WCF 用戶端,以及每個用戶端產生的方法如何傳回唯一命名空間中的記錄集。
/* Procedure that takes account ID and returns record for existing account in the ACCOUNT table */
PROCEDURE get_account(aid IN account.acctid%TYPE, acct OUT account%ROWTYPE) ;
/* Procedure that takes account name and returns record for existing account in the ACCOUNT table */
PROCEDURE get_account(aname IN account.name%TYPE, acct OUT account%ROWTYPE) ;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload1Client : System.ServiceModel.ClientBase<SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload1>, SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload1 {
public microsoft.lobservices.oracledb._2007._03.SCOTT.Package.ACCOUNT_PKG.GET_ACCOUNT.overload1.ACCTRECORD GET_ACCOUNT(System.Nullable<decimal> AID);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload2Client : System.ServiceModel.ClientBase<SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload2>, SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload2 {
public microsoft.lobservices.oracledb._2007._03.SCOTT.Package.ACCOUNT_PKG.GET_ACCOUNT.overload2.ACCTRECORD GET_ACCOUNT(string ANAME);
}
叫用函式和程式
若要使用 WCF 用戶端叫用函式或程式,請執行下列步驟。
產生目標函式、程式或封裝的 WCF 用戶端類別。 這個類別應該包含您將在目標成品上叫用之作業的方法。
注意
在 [新增配接器服務參考 Visual Studio 外掛程式] 中,多載函式和程式會出現在 [可用類別和作業 ] 方塊中,顯示為 [NAME].1、[NAME].2、[NAME].3 等等,其中 [NAME] 是多載成品的名稱,而數值是 Oracle 資料庫上的多載識別碼。
建立 WCF 用戶端類別的實例,並呼叫其方法來叫用函式或程式。
如需如何在 Oracle 資料庫配接器上建立 WCF 用戶端類別和叫用作業的詳細資訊,請參閱 使用 Oracle 資料庫配接器來建立 WCF 服務模型的概觀。
Oracle Database 配接器會在 Oracle 資料庫上的交易內執行每個作業。
重要
代表 REF CURSOR 和 RECORD 類型參數的類別,或在函式或程式中傳回值, (和封裝) 宣告在每個函式或程式的唯一命名空間中。 例如,這表示當做兩個不同函式中傳回值的 PACKAGE REF CURSOR 類型,將會在每個 WCF 用戶端方法的唯一命名空間中宣告。 您必須宣告不同的變數來保存這些不同的傳回值,或在叫用其中一個 WCF 用戶端方法時適當地轉換變數。
下列範例示範如何呼叫多載 /SCOTT/Package/ACCOUNT_PKG/GET_ACCOUNT程式,以從 /SCOTT/ACCOUNT 資料表取得客戶紀錄。 首先,呼叫 /SCOTT/Package/ACCOUNT_PKG/CREATE_ACCOUNT 程式來建立新的記錄。 然後呼叫GET_ACCOUNT的不同多載來讀取新記錄兩次。 本範例使用三個 WCF 用戶端,一個用於CREATE_ACCOUNT程式,一個用於GET_ACCOUNT多載。 別名可用來區別用於傳回值GET_ACCOUNT的命名空間。 SDK 範例中提供完整的範例。 如需 SDK 範例的詳細資訊,請參閱 SDK 中的範例。
using System;
using System.Collections.Generic;
using System.Text;
// Add WCF, WCF Adapter LOB SDK, and Oracle Database adapter namepaces
using System.ServiceModel;
using Microsoft.ServiceModel.Channels;
using Microsoft.Adapters.OracleDB;
// Include this namespace for WCF Adapter LOB SDK and Oracle Database adapter exceptions
using Microsoft.ServiceModel.Channels.Common;
// Alias client namespaces to shorten declarations of "shared" types
using CREATE_ACCOUNTns = microsoft.lobservices.oracledb._2007._03.SCOTT.Package.ACCOUNT_PKG.CREATE_ACCOUNT;
using GET_ACCOUNT_BY_IDns = microsoft.lobservices.oracledb._2007._03.SCOTT.Package.ACCOUNT_PKG.GET_ACCOUNT.overload1;
using GET_ACCOUNT_BY_NAMEns = microsoft.lobservices.oracledb._2007._03.SCOTT.Package.ACCOUNT_PKG.GET_ACCOUNT.overload2;
// This sample demonstrates calling overloaded packaged procedures on Oracle
// First a new account is created by calling CREATE_ACCOUNT which takes two record parameters
// Then the information for the new account is returned by calling an overloaded procedure GET_ACCOUNT
// The first overload returns the account information by account ID
// The second overload returns the account information by account name
// Notice that different clients (and namespaces) are created for overloaded procedures and functions
namespace OracleOverloadsSM
{
class Program
{
static void Main(string[] args)
{
decimal acctId;
string newAccountName = "Paula Bento";
Console.WriteLine("Creating clients");
// Create Client for CREATE_ACCOUNT Function
SCOTTPackageACCOUNT_PKGClient createAccountClient =
new SCOTTPackageACCOUNT_PKGClient("OracleDBBinding_SCOTT.Package.ACCOUNT_PKG");
// NOTE: user name and password are case-sensitive
createAccountClient.ClientCredentials.UserName.UserName = "SCOTT";
createAccountClient.ClientCredentials.UserName.Password = "TIGER";
// Create Client for GET_ACCOUNT Overload 1 -- takes ACCOUNT ID parameter
SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload1Client getAccountByIdClient =
new SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload1Client("OracleDBBinding_SCOTT.Package.ACCOUNT_PKG.GET_ACCOUNT.overload1");
// NOTE: user name and password are case-sensitive
getAccountByIdClient.ClientCredentials.UserName.UserName = "SCOTT";
getAccountByIdClient.ClientCredentials.UserName.Password = "TIGER";
// Create Client for GET_ACCOUNT Overload 2 -- takes ACCOUNT NAME parameter
// NOTE: this client can be created from configuration; detail provided here
// for demonstration
OracleDBBinding overload2Binding = new OracleDBBinding();
EndpointAddress overload2EndpointAddress = new EndpointAddress("oracleDB://ADAPTER");
SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload2Client getAccountByNameClient =
new SCOTTPackageACCOUNT_PKGGET_ACCOUNToverload2Client(overload2Binding, overload2EndpointAddress);
// NOTE: user name and password are case-sensitive
getAccountByNameClient.ClientCredentials.UserName.UserName = "SCOTT";
getAccountByNameClient.ClientCredentials.UserName.Password = "TIGER";
try
{
Console.WriteLine("Opening clients -- please wait");
// Open clients
createAccountClient.Open();
getAccountByIdClient.Open();
getAccountByNameClient.Open();
Console.WriteLine("Creating new account");
// Create an account record
// NOTE: ACCTRECORD is defined in all three namespaces so specify the definition
// that corresponds to the client.
CREATE_ACCOUNTns.ACCTRECORD acctRec = new CREATE_ACCOUNTns.ACCTRECORD();
// Set any value for ACCTID -- new account ID is returned by CREATE_ACCOUNT
acctRec.ACCTID = 0;
acctRec.NAME = newAccountName;
acctRec.BALANCE = 10537;
// Create address record
CREATE_ACCOUNTns.ACCOUNT_PKGADDRESS_REC_TYPERECORD addrRec = new CREATE_ACCOUNTns.ACCOUNT_PKGADDRESS_REC_TYPERECORD();
addrRec.STREET = "456 Valley Rd";
addrRec.CITY = "New York";
addrRec.STATE = "NY";
// Create account
acctId = (decimal)createAccountClient.CREATE_ACCOUNT(acctRec, addrRec);
Console.WriteLine("New Account Created: AccountId = {0}, Name = {1}, Balance = {2:C}",
acctId, acctRec.NAME, acctRec.BALANCE);
/* Get new account by Id */
GET_ACCOUNT_BY_IDns.ACCTRECORD acctById = getAccountByIdClient.GET_ACCOUNT(acctId);
Console.WriteLine("Account Returned by Id: AccountId={0}, Name={1}, Balance={2:C}",
acctById.ACCTID, acctById.NAME, acctById.BALANCE);
/* Get new account by Name */
GET_ACCOUNT_BY_NAMEns.ACCTRECORD acctByName = getAccountByNameClient.GET_ACCOUNT(newAccountName);
Console.WriteLine("Account Returned by Name: AccountId={0}, Name={1}, Balance={2:C}",
acctByName.ACCTID, acctByName.NAME, acctByName.BALANCE);
Console.WriteLine("Hit <RETURN> to finish");
Console.ReadLine();
}
catch (TargetSystemException tex)
{
Console.WriteLine("Exception occurred on the Oracle Database");
Console.WriteLine(tex.InnerException.Message);
}
catch (ConnectionException cex)
{
Console.WriteLine("Exception occurred connecting to the Oracle Database");
Console.WriteLine(cex.InnerException.Message);
}
catch (Exception ex)
{
Console.WriteLine("Exception is: " + ex.Message);
if (ex.InnerException != null)
{
Console.WriteLine("Inner Exception is: " + ex.InnerException.Message);
}
throw ex;
}
finally
{
// Close all the clients
createAccountClient.Close();
getAccountByIdClient.Close();
getAccountByNameClient.Close();
}
}
}
}