使用 ODP.NET 和引用游标优化结果集

来源:互联网 发布:淘宝全球购物网 编辑:程序博客网 时间:2024/06/08 04:16
http://linglong117.blog.163.com/blog/static/2771454720075199523277/
  利用 Oracle Data Provider for .NET,可以通过多种方法将  Oracle 数据库中的查询结果返回给客户端应用程序;最强大、最灵活、最具伸缩性的方法之一是使用引用游标。  本文介绍了引用游标及它的应用,其中包括一个将多个活动结果集用于 Oracle 的示例。 此示例代码演示了在 .NET  代码中使用引用游标的极其简单的过程。 如果您刚刚开始使用 Oracle Data Provider for .NET,请参阅 John  Paul Cook 的文章“基于 Oracle 数据库构建 .NET 应用程序”,了解结合使用提供程序与 Visual Studio .NET 开发环境的过程。   
    前提条件  Oracle9i 数据库或 Oracle 数据库 10g 的访问权限 HR 示例用户的访问权限Oracle Client 9i 第 2 版或更高版本 Oracle Data Provider for .NET Microsoft Visual Studio .NET 2002 或更高版本    
    什么是引用游标?   
    如果您并不熟悉引用游标,那么您提出的第一个问题自然就是“到底什么是引用游标?”  简单而言,引用游标是一个 PL/SQL 数据类型,它的值为一个地址值,用于表示查询工作区在数据库服务器上的内存位置。  您接下来可能又想要知道什么是查询区。 可以将查询工作区看作是服务器上的结果集(有时称作行集)- 它是查询结果在服务器内存中的存储位置。  当您开始看到“查询工作区”和“内存地址”这样的术语时,您可能开始认为引用游标比较复杂并需要处理 C 样式指针等对象。 幸运地是,Oracle  Data Provider for .NET 并不存在这样的情况。 实际上,在使用 Oracle Data Provider for .NET  时,可以将引用游标只看作是服务器上的结果集的句柄。 由于引用游标是一个 PL/SQL 数据类型,因此需要通过某种方法在 .NET  代码中表示引用游标,可以通过 Oracle Data Provider for .NET 公开的 OracleRefCursor 类完成此操作。   
    引用游标的特性   
    引用游标有几个重要特性必须要考虑到,只有这样才能在代码中正确地结合使用引用游标与 Oracle Data Provider for .NET :   
  引用游标引用服务器内存。 引用游标表示的内存地址“驻留”在数据库服务器上,而非客户端计算机上。 这意味着客户端必须在引用游标的生命周期期间保持数据库连接。 如果基础数据库连接关闭,将无法从客户端访问引用游标。
  引用游标涉及额外的数据库往返。由于引用游标是指向服务器上的内存的指针,该指针要返回至客户端,而引用游标中包含的实际数据最初并不返回至客户端。 例如,当客户端通过调用 OracleCommand 对象的 ExecuteNonQuery  方法打开引用游标时,将只返回数据在服务器上的内存地址。 客户端必有在打开引用游标后请求引用游标中包含的数据。  尽管它需要额外的往返,但这在某些情况下对性能是很有好处的。  在用户尝试读取数据之前将不检索数据,从而可以防止从存储过程返回许多查询结果时可能出现的瓶颈。 
  引用游标无法更新。引用游标表示的结果集是只读的。 无法通过引用游标更新数据库。
  引用游标无法向后滚动。只能以向前的、顺次的方式访问引用游标表示的数据。 不能将记录指针置于引用游标的内部,以指向结果集中的随机记录。
  引用游标是一个 PL/SQL 数据类型。 请在 PL/SQL 代码块内部创建和返回引用游标。    
  引用游标可以是弱类型或强类型的。强  类型的引用游标包含一个返回类型,该返回类型是在 PL/SQL 中声明引用游标本身时定义的。  与强类型的引用游标相比,弱类型的引用游标没有定义返回类型,这意味着弱类型的引用游标可以引用任何类型的查询工作区。  而强类型的引用游标只能引用特定类型的查询工作区,即该工作区的类型(或结构)必须与声明引用游标时使用的类型(或结构)相同。  换言之,强类型的引用游标是特定的,而弱类型的引用游标是一般的。 本文使用弱类型的引用游标。     
    OracleRefCursor 类   
    前面已经进行过简单介绍,在 .NET 代码中表示引用光标是通过 OracleRefCursor 类实现的,该类由 Oracle Data Provider for .NET 在 Oracle.DataAccess.Types 命名空间中公开。 OracleRefCursor 类是一个简单类,该类没有构造函数,它将 GetDataReader 方法公开为一种数据访问方法,用于访问服务器上的查询工作区中存储的数据。 还可以将 OracleRefCursor 类与 OracleDataAdapter 类结合使用以填充 DataTables 和 DataSets。 由于 OracleRefCursor 类没有构造函数,因此不要采用标准方法来完成此类对象的实例化。 而是创建 OracleParameter 类的实例并将 OracleDbType 属性设置为值 RefCursor。请注意,引用游标是一个 PL/SQL 数据类型,因此必须使用 OracleParameter 类的实例将引用光标作为参数传出 PL/SQL 块。 此外,还可以将引用游标作为输出参数或函数返回值传递给调用客户端。 在 Oracle 数据库 10g 第 2 版的 ODP.NET 中,可以将引用光标作为输入参数传递。   
    为什么使用 PL/SQL 和引用游标?   
    此时,您已经知道什么是引用游标,了解了引用游标的某些重要属性,并知道需要将 OracleRefCursor 类与 OracleParameter 类结合使用以将 PL/SQL 中的引用游标传递到 .NET 代码中。   
    人们通常问我的两个相关问题是“不能只将 SQL 语句嵌入到代码中并使用 OracleCommand 从数据库中获取数据吗?”和“如果可以的话,为什么还要使用 PL/SQL 和引用游标?”   
    我对第一个问题的回答是“是的,可以”。我对第二个问题的回答是“根据情况的不同,这样做是有意义的”。  下面我将进行解释。 首先,可以创建整个应用程序而不必编写或调用任何 PL/SQL 代码行。 而引用游标有助于优化 Oracle 数据检索。  使用 PL/SQL 的主要好处之一是它与 Oracle 数据库和 SQL 语言紧密集成在一起。 例如,表中的 Oracle 列类型通常是  PL/SQL 数据类型,反之亦然。 这样,您只用处理一个变量,该变量既是数据库中的表的正确数据类型,也是所使用的编程语言的正确数据类型。  另一个有时忽略的好处是您可以将 PL/SQL 用作安全工具或机制。 可以创建一个 PL/SQL 过程,用于返回用户无法直接访问(他们只能通过  PL/SQL 代码访问数据)的数据库表中的数据。 用户需要有 PL/SQL  过程或函数的相应执行权限才能顺利的使用此方案,数据库管理员负责授予这些权限。 此外,通过使用  PL/SQL,您已经将处理数据的代码移动到数据库中,并完成了客户端逻辑与数据逻辑的分离。  将代码移动到数据库中即是完成了代码的集中,因此只需要在一个位置管理它。   
    引用游标的主要用途是使 PL/SQL 代码能够将结果集返回给用其他语言编写并位于数据库外部的程序。 它是 PL/SQL 代码将结果集返回至客户端应用程序所采用的机制。 如果要将 PL/SQL 代码中的结果集返回至客户端,可以使用引用游标完成此操作。   
    尽管有很多的原因促使我们采用 PL/SQL , .NET 程序员最初可能会觉得将代码移出  .NET 环境并移入数据库有些不自然。 但请注意,PL/SQL 是为处理 Oracle 数据库中的数据而创建的,并且它的效果很好。  实际上,最新的数据库版本(尤其是 Oracle 数据库 10g)引入了 PL/SQL 编译器和优化器的增强功能,因此从纯性能的角度来看,PL/SQL 是非常吸引人的。   
    PL/SQL 程序包和程序包体   
    如果您刚接触 Oracle,则可能对 PL/SQL 程序包和程序包体不太熟悉。 程序包是 PL/SQL 从 Ada(PL/SQL 所基于的语言)继承来的结构。 简单地说,PL/SQL 程序包是一个用于将相关项目存储或捆绑为逻辑实体的机制。 程序包由两个不同的部分组成:   
  程序包规范。定义程序包中包含的内容,类似某种语言(如 C++)中的头文件。 规范中定义的项目是公共的。 即,规范和主体外部的代码可以“看到”这些项目。 规范是已发布的程序包接口。
    程序包主体。包含规范中定义的过程和函数的代码。 主体可能还包含规范中未声明的代码;这种情况下,此代码是专用的并且只对程序包主体内的代码可见。    
    这两个部分在数据字典中作为单独对象分开存储,并可以在 user_source 视图中看到。 规范存储为 PACKAGE 类型,主体存储为 PACKAGE BODY 类型。 注意,可以拥有一个无主体的规范。 但不能有一个无规范的主体。 例如,可以使用无主体的规范声明一组公共常量;由于一组常量不需要实现,因此主体不是必要的。 可以通过使用用于 Visual Studio .NET 的 Oracle 开发人员工具查看程序包主体和规范。   
    示例应用程序   
    既然您已经牢固掌握了在 .NET 应用程序中使用引用游标时所涉及的各种概念和结构,现在我们将了解一些代码以创建一个控制台应用程序示例,用于演示将各个部分组合在一起的过程。 由于您要使用客户端应用程序中的 OracleDataReader 和 DataSet 类的实例从引用游标检索数据,因此可以很方便对此示例加以更改,以作为传统 Windows 客户端或 ASP.NET 客户端工作。 您将使用 HR 示例模式,它是 Oracle9i 和 Oracle 10g 软件附带的示例模式之一。 此示例应用程序将检索 HR 模式中的 EMPLOYEES 表中的列和行的子集,并将结果显示在控制台窗口中。 您需要使用过程的函数返回值和输出参数。   
    PL/SQL 代码   
    您可以先创建 PL/SQL 代码或 .NET 代码;但由于您将需要知道要在 .NET  代码中使用的程序包、函数和过程的名称,因此先创建 PL/SQL 代码更合乎逻辑。 要创建 PL/SQL 程序包和程序包主体,请以 HR  用户的身份使用 SQL*Plus 登录到数据库。 注意,HR 用户在默认情况下处于锁定状态。 在登录到数据库之前,您必须解除帐户锁定。  成功登录到数据库后,请执行 otn_ref_cursor.sql 脚本以创建 PL/SQL 程序包和程序包主体。 此脚本包含在示例代码下载文件中。 下载文件中所包含的 README.txt 文件提供了执行此脚本的详细信息。 以下是 otn_ref_cursor.sql 文件:   
  create or replace package otn_ref_cursor as
  -- used to illustrate passing a ref cursor
  -- as a return value from a function
  -- or as an output parameter from a procedure

  function get_emp_info return sys_refcursor;
  procedure get_emp_info(p_rc out sys_refcursor);

  procedure get_multiple_cursors(p_rc1 out sys_refcursor,
                                 p_rc2 out sys_refcursor,
                                 p_rc3 out sys_refcursor);
end;
/
    
  现在,您已经创建了 PL/SQL 程序包,下面便可以创建 PL/SQL 程序包主体。 以下用于创建 PL/SQL 程序包主体的代码也是 otn_ref_cursor.sql 文件中的一部分:   
  create or replace package body otn_ref_cursor as
  function get_emp_info return sys_refcursor is
    -- declare the cursor variable
    -- sys_refcursor is a built in type
    l_cursor sys_refcursor;
begin
    open l_cursor for
    select   employee_id,
             last_name,
             first_name,
             to_char(hire_date, 'DD-MON-YYYY') hire_date
    from     employees
    where    last_name like 'A%'
    order by last_name,
             first_name;

    return l_cursor;
end;

  procedure get_emp_info(p_rc out sys_refcursor) is
begin
    -- open the cursor using the passed in ref cursor
    -- sys_refcursor is a built in type
    open p_rc for
    select   employee_id,
             last_name,
             first_name,
             to_char(hire_date, 'DD-MON-YYYY') hire_date
    from     employees
    where    last_name like 'A%'
    order by last_name,
             first_name;
end;

  procedure get_multiple_cursors(p_rc1 out sys_refcursor,
                                 p_rc2 out sys_refcursor,
                                 p_rc3 out sys_refcursor) is
begin
    -- open the cursors using the passed in ref cursor parameters
    -- sys_refcursor is a built in type
    open p_rc1 for
    select   employee_id,
             last_name,
             first_name,
             to_char(hire_date, 'DD-MON-YYYY') hire_date
    from     employees
    where    last_name like 'A%'
    order by last_name,
             first_name;

    open p_rc2 for
    select   employee_id,
             last_name,
             first_name,
             to_char(hire_date, 'DD-MON-YYYY') hire_date
    from     employees
    where    last_name like 'B%'
    order by last_name,
             first_name;

    open p_rc3 for
    select   employee_id,
             last_name,
             first_name,
             to_char(hire_date, 'DD-MON-YYYY') hire_date
    from     employees
    where    last_name like 'C%'
    order by last_name,
             first_name;
end;
end;
/
    
  类方法   
    在创建类方法的过程中,我们展示了不同引用游标使用方法。 此外,您还将创建“helper”类方法,以将结果显示到控制台窗口:   
  DisplayRefCursorData 方法: 此方法是一个的重载方法,用来显示 DataSet 对象或 OracleDataReader 对象中的所有数据。DisplayDataReaderRow 方法: 此方法用于显示 OracleDataReader 对象中的一行数据。GetCursorFunction 方法: 此方法用于将引用游标作为函数返回值进行检索。GetCursorParameter 方法: 此方法用于将引用游标作为过程中的输出参数进行检索。TraverseResultSets 方法: 此方法用于检索多个游标并演示了如何顺次遍历每个结果集。MultipleActiveResultSets 方法: 此方法用于检索和“随机”处理多个活动的结果集。    
    Main 方法   
    示例代码中的 Main 方法的用途是建立一个数据库连接,然后调用每个成员方法以演示如何使用引用游标。注意: 要运行此示例,请确保修改连接字符串中的User Id、Password 和 Data Source 参数(如果它们不同于下面的参数)。   
  
// C#
static void Main(string[] args)
{
  // create a connection to the database
  // change values as needed for your environment
  OracleConnection con = new OracleConnection("User Password=hr; Data Source=otndemo; Pooling=false");

// attempt to open the connection
try
  {
con.Open();
  }
  catch (OracleException ex)
  {
    Console.WriteLine(ex.Message);
  }

  // only call our methods if we are connected
  // to the database
if (con.State == ConnectionState.Open)
  {
    // call method that gets a ref cursor from pl/sql function
    GetCursorFunction(con);

    // call method that gets a ref cursor from pl/sql procedure
    GetCursorParameter(con);

    // call method that serially traverses multiple result sets
    TraverseResultSets(con);

    // call method that illustrates multiple active result sets (MARS)
    MultipleActiveResultSets(con);
  }

  // clean up the connection object
  con.Dispose();
}

' Visual Basic .NET
Sub Main()
  ' create a connection to the database
  ' change values as needed for your environment
  Dim con As OracleConnection = New OracleConnection
      ("User Source=otndemo;Pooling=false")

' attempt to open the connection
Try
con.Open()
  Catch ex As OracleException
    Console.WriteLine(ex.Message)
End Try

  ' only call our methods if we are connected
  ' to the database
If con.State = ConnectionState.Open Then
    ' call method that gets a ref cursor from pl/sql function
    GetCursorFunction(con)

    ' call method that gets a ref cursor from pl/sql procedure
    GetCursorParameter(con)

    ' call method that serially traverses multiple result sets
    TraverseResultSets(con)

    ' call method that illustrates multiple active result sets (MARS)
    MultipleActiveResultSets(con)
End If

  con.Dispose()
End Sub
    
  用于演示如何使用引用游标的各种方法全部遵循同一模式。 每个方法都创建一个用于调用数据库中的 PL/SQL 代码的 OracleCommand 对象。 OracleCommand 对象的 CommandType 属性设置为值 CommandType.StoredProcedure,以指示命令文本表示数据库中存储的 PL/SQL 代码的名称。 OracleCommand 对象的命令文本和数据库连接在 OracleCommand 对象构造函数调用中初始化。 创建 OracleCommand 对象后,将创建一个 OracleParameter 对象。 该对象将表示 .NET 代码中的引用游标。 可以通过将每个参数对象的 OracleDbType 属性设置为 OracleDbType.RefCursor 来完成此任务。 使用引用游标时必须要正确设置此属性。 根据您是调用前面创建的 PL/SQL 程序包中的函数还是过程,适当设置 ParameterDirection 属性值。 此参数随后将添加到命令对象集合中,并执行。 随后使用 OracleDataAdapter 访问引用光标,可将其当做 OracleDataReader 对象或 DataSet 进行访问。 最后,处理对象以释放资源。   
    GetCursorFunction 方法代码调用 PL/SQL 程序包中的 get_emp_info 函数。 使用 PL/SQL 函数时,正确声明 ParameterDirection(如本文中的示例所示)是很重要的。 此代码如下:   
  // C#
static void GetCursorFunction(OracleConnection con)
{
  // display a simple marker line to the console
  // to indicate where we are
  Console.WriteLine("In GetCursorFunction...");
Console.WriteLine();

  // create the command object and set attributes
  OracleCommand cmd = new OracleCommand("otn_ref_cursor.get_emp_info", con);
cmd.CommandType = CommandType.StoredProcedure;

  // create parameter object for the cursor
  OracleParameter p_refcursor = new OracleParameter();

  // this is vital to set when using ref cursors
  p_refcursor.OracleDbType = OracleDbType.RefCursor;

  // this is a function return value so we must indicate that fact
  p_refcursor.Direction = ParameterDirection.ReturnValue;

  // add the parameter to the collection
  cmd.Parameters.Add(p_refcursor);

  // create a data adapter to use with the data set
  OracleDataAdapter da = new OracleDataAdapter(cmd);

  // create the data set
  DataSet ds = new DataSet();

  // fill the data set
  da.Fill(ds);

  // display the data to the console window
  DisplayRefCursorData(ds);

  // clean up our objects release resources
ds.Dispose();
da.Dispose();
  p_refcursor.Dispose();
cmd.Dispose();

Console.WriteLine();
}

' Visual Basic .NET
Sub GetCursorFunction(ByVal con As OracleConnection)
  ' display a simple marker line to the console
  ' to indicate where we are
  Console.WriteLine("In GetCursorFunction...")
Console.WriteLine()

  ' create the command object and set attributes
  Dim cmd As OracleCommand = New OracleCommand("otn_ref_cursor.get_emp_info", con)
cmd.CommandType = CommandType.StoredProcedure

  ' create parameter object for the cursor
  Dim p_refcursor As OracleParameter = New OracleParameter

  ' this is vital to set when using ref cursors
  p_refcursor.OracleDbType = OracleDbType.RefCursor

  ' this is a function return value so we must indicate that fact
  p_refcursor.Direction = ParameterDirection.ReturnValue

  ' add the parameter to the collection
  cmd.Parameters.Add(p_refcursor)

  ' create a data adapter to use with the data set
  Dim da As OracleDataAdapter = New OracleDataAdapter(cmd)

  ' create the data set
  Dim ds As DataSet = New DataSet

  ' fill the data set
  da.Fill(ds)

  ' display the data to the console window
  DisplayRefCursorData(ds)

  ' clean up our objects release resources
  ds.Dispose()
  da.Dispose()
  p_refcursor.Dispose()
cmd.Dispose()

Console.WriteLine()
End Sub
    
  GetCursorParameter 方法代码调用 PL/SQL 程序包中的 get_emp_info 过程。 使用 PL/SQL 函数时便存在这种情况,使用过程中的输出参数时正确声明 ParameterDirection 是很重要的。 此代码如下:   
  
// C#
static void GetCursorParameter(OracleConnection con)
{
  // display a simple marker line to the console
  // to indicate where we are
  Console.WriteLine("In GetCursorParameter...");
Console.WriteLine();

  // create the command object and set attributes
  OracleCommand cmd = new OracleCommand("otn_ref_cursor.get_emp_info", con);
cmd.CommandType = CommandType.StoredProcedure;

  // create parameter object for the cursor
  OracleParameter p_refcursor = new OracleParameter();

  // this is vital to set when using ref cursors
  p_refcursor.OracleDbType = OracleDbType.RefCursor;

  // this is an output parameter so we must indicate that fact
  p_refcursor.Direction = ParameterDirection.Output;

  // add the parameter to the collection
  cmd.Parameters.Add(p_refcursor);

  // create a data adapter to use with the data set
  OracleDataAdapter da = new OracleDataAdapter(cmd);

  // create the data set
  DataSet ds = new DataSet();

  // fill the data set
  da.Fill(ds);

  // display the data to the console window
  DisplayRefCursorData(ds);

  // clean up our objects release resources
ds.Dispose();
da.Dispose();
  p_refcursor.Dispose();
cmd.Dispose();

Console.WriteLine();
}

' Visual Basic .NET
Sub GetCursorParameter(ByVal con As OracleConnection)
  ' display a simple marker line to the console
  ' to indicate where we are
  Console.WriteLine("In GetCursorParameter...")
Console.WriteLine()

  ' create the command object and set attributes
  Dim cmd As OracleCommand = New OracleCommand("otn_ref_cursor.get_emp_info", con)
cmd.CommandType = CommandType.StoredProcedure

  ' create parameter object for the cursor
  Dim p_refcursor As OracleParameter = New OracleParameter

  ' this is vital to set when using ref cursors
  p_refcursor.OracleDbType = OracleDbType.RefCursor

  ' this is an output parameter so we must indicate that fact
  p_refcursor.Direction = ParameterDirection.Output

  ' add the parameter to the collection
  cmd.Parameters.Add(p_refcursor)

  ' create a data adapter to use with the data set
  Dim da As OracleDataAdapter = New OracleDataAdapter(cmd)

  ' create the data set
  Dim ds As DataSet = New DataSet

  ' fill the data set
  da.Fill(ds)

  ' display the data to the console window
  DisplayRefCursorData(ds)

  ' clean up our objects release resources
  ds.Dispose()
  da.Dispose()
  p_refcursor.Dispose()
cmd.Dispose()

Console.WriteLine()
End Sub
    
  TraverseResultSets 方法代码在单个数据库调用中检索多个游标并演示了利用 Oracle Data Provider for .NET 实现顺次访问结果集的过程。   
  
// C#
static void TraverseResultSets(OracleConnection con)
{
  // display a simple marker line to the console
  // to indicate where we are
  Console.WriteLine("In TraverseResultSets...");
Console.WriteLine();

  // create the command object and set attributes
  OracleCommand cmd = new OracleCommand("otn_ref_cursor.get_multiple_cursors", con);
cmd.CommandType = CommandType.StoredProcedure;

  // create parameter objects for the cursors
  OracleParameter p_rc1 = new OracleParameter();
  OracleParameter p_rc2 = new OracleParameter();
  OracleParameter p_rc3 = new OracleParameter();

  // this is vital to set when using ref cursors
  p_rc1.OracleDbType = OracleDbType.RefCursor;
  p_rc2.OracleDbType = OracleDbType.RefCursor;
  p_rc3.OracleDbType = OracleDbType.RefCursor;

  // these are output parameters so we must indicate that fact
p_rc1.Direction = ParameterDirection.Output;
p_rc2.Direction = ParameterDirection.Output;
p_rc3.Direction = ParameterDirection.Output;

  // add the parameters to the collection
  cmd.Parameters.Add(p_rc1);
  cmd.Parameters.Add(p_rc2);
  cmd.Parameters.Add(p_rc3);

  // work with an OracleDataReader rather
  // than a DataSet to illustrate ODP.NET features
OracleDataReader dr = cmd.ExecuteReader();

  // display the data in the first ref cursor
  Console.WriteLine("Displaying ref cursor #1:");
  DisplayRefCursorData(dr);
Console.WriteLine();

  // the Oracle Data Provider follows the standard
  // by exposing the NextResult method to traverse
  // multiple result sets
  
  // display the data in the second ref cursor
  if (dr.NextResult())
  {
    Console.WriteLine("Displaying ref cursor #2:");
    DisplayRefCursorData(dr);
Console.WriteLine();
  }

  // display the data in the third ref cursor
  if (dr.NextResult())
  {
    Console.WriteLine("Displaying ref cursor #3:");
    DisplayRefCursorData(dr);
Console.WriteLine();
  }

  // clean up our objects and release resources
dr.Dispose();
  p_rc1.Dispose();
  p_rc2.Dispose();
  p_rc3.Dispose();
cmd.Dispose();
}

' Visual Basic .NET
Sub TraverseResultSets(ByVal con As OracleConnection)
  ' display a simple marker line to the console
  ' to indicate where we are
  Console.WriteLine("In TraverseResultSets...")
Console.WriteLine()

  ' create the command object and set attributes
  Dim cmd As OracleCommand = New OracleCommand("otn_ref_cursor.get_multiple_cursors", con)
cmd.CommandType = CommandType.StoredProcedure

  ' create parameter objects for the cursors
Dim p_rc1 As OracleParameter = New OracleParameter
Dim p_rc2 As OracleParameter = New OracleParameter
Dim p_rc3 As OracleParameter = New OracleParameter

  ' this is vital to set when using ref cursors
  p_rc1.OracleDbType = OracleDbType.RefCursor
  p_rc2.OracleDbType = OracleDbType.RefCursor
  p_rc3.OracleDbType = OracleDbType.RefCursor

  ' these are output parameters so we must indicate that fact
  p_rc1.Direction = ParameterDirection.Output
  p_rc2.Direction = ParameterDirection.Output
  p_rc3.Direction = ParameterDirection.Output

  ' add the parameters to the collection
  cmd.Parameters.Add(p_rc1)
  cmd.Parameters.Add(p_rc2)
  cmd.Parameters.Add(p_rc3)

  ' work with an OracleDataReader rather
  ' than a DataSet to illustrate ODP.NET features
Dim dr As OracleDataReader = cmd.ExecuteReader()

  ' display the data in the first ref cursor
  Console.WriteLine("Displaying ref cursor #1:")
  DisplayRefCursorData(dr)
Console.WriteLine()

  ' the Oracle Data Provider follows the standard
  ' by exposing the NextResult method to traverse
  ' multiple result sets

  ' display the data in the second ref cursor
  If (dr.NextResult()) Then
    Console.WriteLine("Displaying ref cursor #2:")
    DisplayRefCursorData(dr)
Console.WriteLine()
End If

  ' display the data in the third ref cursor
  If (dr.NextResult()) Then
    Console.WriteLine("Displaying ref cursor #3:")
    DisplayRefCursorData(dr)
Console.WriteLine()
End If

  ' clean up our objects and release resources
dr.Dispose()
  p_rc1.Dispose()
  p_rc2.Dispose()
  p_rc3.Dispose()
cmd.Dispose()
End Sub
    
  MultipleActiveResultSets  方法检索和“随机”处理同时处于活动状态的多个结果集,演示了 Oracle Data Provider for .NET 的特性。 在第一版的  ODP.NET 中就已经推出了此特性。此外,请注意,此代码在处理过程中“跳过”第二个引用游标。 将第一个和第三个结果集检索至 .NET  客户端,但推迟了对第二个结果集的数据检索并一直保存在数据库服务器上。  由于第二个结果集的数据检索可以一直延迟到需要的时候进行,因此可缩短响应时间。   
  
// C#
static void MultipleActiveResultSets(OracleConnection con)
{
  // display a simple marker line to the console
  // to indicate where we are
  Console.WriteLine("In MultipleActiveResultSets...");
Console.WriteLine();

  // create the command object and set attributes
  OracleCommand cmd = new OracleCommand("otn_ref_cursor.get_multiple_cursors", con);
cmd.CommandType = CommandType.StoredProcedure;

  // create parameter objects for the cursors
  OracleParameter p_rc1 = new OracleParameter();
  OracleParameter p_rc2 = new OracleParameter();
  OracleParameter p_rc3 = new OracleParameter();

  // this is vital to set when using ref cursors
  p_rc1.OracleDbType = OracleDbType.RefCursor;
  p_rc2.OracleDbType = OracleDbType.RefCursor;
  p_rc3.OracleDbType = OracleDbType.RefCursor;

  // these are output parameters so we must indicate that fact
p_rc1.Direction = ParameterDirection.Output;
p_rc2.Direction = ParameterDirection.Output;
p_rc3.Direction = ParameterDirection.Output;

  // add the parameters to the collection
  cmd.Parameters.Add(p_rc1);
  cmd.Parameters.Add(p_rc2);
  cmd.Parameters.Add(p_rc3);

  // execute the command to open the ref cursors
cmd.ExecuteNonQuery();

  // work with an OracleDataReader rather
  // than a DataSet to illustrate ODP.NET features
  OracleDataReader dr1 = ((OracleRefCursor) p_rc1.Value).GetDataReader();

  // notice we are skipping the second (or "middle") ref cursor
  OracleDataReader dr3 = ((OracleRefCursor) p_rc3.Value).GetDataReader();

  // illustrate the multiple result sets are active
  // by "randomly" displaying data from each one
  if (dr1.Read())
  {
    Console.WriteLine("Displaying data from ref cursor #1:");
    DisplayDataReaderRow(dr1);
Console.WriteLine();
  }

  if (dr3.Read())
  {
    Console.WriteLine("Displaying data from ref cursor #3:");
    DisplayDataReaderRow(dr3);
Console.WriteLine();
  }

  if (dr1.Read())
  {
    Console.WriteLine("Displaying data from ref cursor #1:");
    DisplayDataReaderRow(dr1);
Console.WriteLine();
  }
  
  if (dr3.Read())
  {
    Console.WriteLine("Displaying data from ref cursor #3:");
    DisplayDataReaderRow(dr3);
Console.WriteLine();
  }

  // clean up our objects and release resources
  dr1.Dispose();
  dr3.Dispose();
  p_rc1.Dispose();
  p_rc2.Dispose();
  p_rc3.Dispose();
cmd.Dispose();
}

' Visual Basic .NET
Sub MultipleActiveResultSets(ByVal con As OracleConnection)
  ' display a simple marker line to the console
  ' to indicate where we are
  Console.WriteLine("In MultipleActiveResultSets...")
Console.WriteLine()

  ' create the command object and set attributes
  Dim cmd As OracleCommand = New OracleCommand("otn_ref_cursor.get_multiple_cursors", con)
cmd.CommandType = CommandType.StoredProcedure

  ' create parameter objects for the cursors
Dim p_rc1 As OracleParameter = New OracleParameter
Dim p_rc2 As OracleParameter = New OracleParameter
Dim p_rc3 As OracleParameter = New OracleParameter

  ' this is vital to set when using ref cursors
  p_rc1.OracleDbType = OracleDbType.RefCursor
  p_rc2.OracleDbType = OracleDbType.RefCursor
  p_rc3.OracleDbType = OracleDbType.RefCursor

  ' these are output parameters so we must indicate that fact
  p_rc1.Direction = ParameterDirection.Output
  p_rc2.Direction = ParameterDirection.Output
  p_rc3.Direction = ParameterDirection.Output

  ' add the parameters to the collection
  cmd.Parameters.Add(p_rc1)
  cmd.Parameters.Add(p_rc2)
  cmd.Parameters.Add(p_rc3)

  ' execute the command to open the ref cursors
cmd.ExecuteNonQuery()

  ' work with an OracleDataReader rather
  ' than a DataSet to illustrate ODP.NET features
  Dim dr1 As OracleDataReader = DirectCast(p_rc1.Value, OracleRefCursor).GetDataReader()

  ' notice we are skipping the second (or "middle") ref cursor
  Dim dr3 As OracleDataReader = DirectCast(p_rc3.Value, OracleRefCursor).GetDataReader()

  ' illustrate the multiple result sets are active
  ' by "randomly" displaying data from each one
  If (dr1.Read()) Then
    Console.WriteLine("Displaying data from ref cursor #1:")
    DisplayDataReaderRow(dr1)
Console.WriteLine()
End If

  If (dr3.Read()) Then
    Console.WriteLine("Displaying data from ref cursor #3:")
    DisplayDataReaderRow(dr3)
Console.WriteLine()
End If

  If (dr1.Read()) Then
    Console.WriteLine("Displaying data from ref cursor #1:")
    DisplayDataReaderRow(dr1)
Console.WriteLine()
End If

  If (dr3.Read()) Then
    Console.WriteLine("Displaying data from ref cursor #3:")
    DisplayDataReaderRow(dr3)
Console.WriteLine()
End If

  ' clean up our objects and release resources
  dr1.Dispose()
  dr3.Dispose()
  p_rc1.Dispose()
  p_rc2.Dispose()
  p_rc3.Dispose()
cmd.Dispose()
End Sub
    
原创粉丝点击