使用 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 客户端调用函数或过程,请执行以下步骤。

  1. 为目标函数、过程或包生成 WCF 客户端类。 此类应包含要对目标项目调用的操作的方法。

    注意

    在“添加适配器服务引用 Visual Studio 插件”中,重载的函数和过程在 “可用类别和操作 ”框中显示为 [NAME].1、[NAME].2、[NAME].3 等,其中 [NAME] 是重载项目的名称,数值是 Oracle 数据库上的重载 ID。

  2. 创建 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();  
            }  
  
        }  
    }  
}  

另请参阅

使用 WCF 服务模型开发 Oracle 数据库应用程序