使用 WCF 服务模型在 Oracle 数据库中调用函数和过程
适用于 Oracle 数据库的 Microsoft BizTalk 适配器将过程、函数和包显示为操作。 在 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 重载过程。 此过程基于帐户 ID 或帐户名称从 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 参数作为复杂 XML 类型返回的结果集,这些类型包含行数据 (或 oracle 记录) 字段。 在 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 行为。
以下示例演示了在 SCOTT 架构) 加载 (的简单 Oracle 过程的一部分,以及为调用它而生成的 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 数据库适配器通过将唯一字符串追加到节点 ID 以及它为每个重载项目显示的命名空间,支持重载的过程、函数和包。 对于第一个重载,此字符串为“overload1”,对于下一个重载为“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 数据库维护的项目的重载 ID。
以下示例显示了 WCF 客户端,以及为 ACCOUNT_PKG 包中的重载GET_ACCOUNT过程生成的方法签名。 (包含 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 数据库上的重载 ID。
创建 WCF 客户端类的实例并调用其方法来调用函数或过程。
有关如何在 Oracle 数据库适配器上创建 WCF 客户端类和调用操作的更多详细信息,请参阅 使用 Oracle 数据库适配器的 WCF 服务模型概述。
Oracle 数据库适配器在 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();
}
}
}
}