Oracle Account
Manage your account and access personalized content.
Sign up for an Oracle Account
Sign in to Cloud
Access your cloud dashboard, manage orders, and more.
Sign up for a free trial
查看完整的“精通 Oracle 的 .NET 应用程序开发”目录
利用 Oracle Data Provider for .NET,可以通过多种方法将 Oracle 数据库中的查询结果返回给客户端应用程序;最强大、最灵活、最具伸缩性的方法之一是使用引用游标。 本文介绍了引用游标及它的应用,其中包括一个将多个活动结果集用于 Oracle 的示例。 此示例代码演示了在 .NET 代码中使用引用游标的极其简单的过程。 如果您刚刚开始使用 Oracle Data Provider for .NET,请参阅 John Paul Cook 的文章“
基于 Oracle 数据库构建 .NET 应用程序
”,了解结合使用提供程序与 Visual Studio .NET 开发环境的过程。
Oracle9
i
数据库或 Oracle 数据库 10
g
的访问权限
HR 示例用户的访问权限
Oracle Client 9
i
第 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 数据库 10
g
第 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 数据库 10
g
)引入了 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 示例模式,它是 Oracle9
i
和 Oracle 10
g
软件附带的示例模式之一。 此示例应用程序将检索 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);
现在,您已经创建了 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;
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;
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;
在创建类方法的过程中,我们展示了不同引用游标使用方法。 此外,您还将创建“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 Id=hr; Password=hr; Data Source=otndemo; Pooling=false");
// attempt to open the connection
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 Id=hr;Password=hr;Data Source=otndemo;Pooling=false")
' attempt to open the connection
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
运行示例应用程序
现在您已经创建了所有必需的组件和代码,下面便可以运行此示例并在控制台窗口中查看它的输出。 以下是输出的内容:
In GetCursorFunction...
174, Abel, Ellen, 11-MAY-1996
166, Ande, Sundar, 24-MAR-2000
130, Atkinson, Mozhe, 30-OCT-1997
105, Austin, David, 25-JUN-1997
In GetCursorParameter...
174, Abel, Ellen, 11-MAY-1996
166, Ande, Sundar, 24-MAR-2000
130, Atkinson, Mozhe, 30-OCT-1997
105, Austin, David, 25-JUN-1997
In TraverseResultSets...
Displaying ref cursor #1:
174, Abel, Ellen, 11-MAY-1996
166, Ande, Sundar, 24-MAR-2000
130, Atkinson, Mozhe, 30-OCT-1997
105, Austin, David, 25-JUN-1997
Displaying ref cursor #2:
204, Baer, Hermann, 07-JUN-1994
116, Baida, Shelli, 24-DEC-1997
167, Banda, Amit, 21-APR-2000
172, Bates, Elizabeth, 24-MAR-1999
192, Bell, Sarah, 04-FEB-1996
151, Bernstein, David, 24-MAR-1997
129, Bissot, Laura, 20-AUG-1997
169, Bloom, Harrison, 23-MAR-1998
185, Bull, Alexis, 20-FEB-1997
Displaying ref cursor #3:
187, Cabrio, Anthony, 07-FEB-1999
148, Cambrault, Gerald, 15-OCT-1999
154, Cambrault, Nanette, 09-DEC-1998
110, Chen, John, 28-SEP-1997
188, Chung, Kelly, 14-JUN-1997
119, Colmenares, Karen, 10-AUG-1999
In MultipleActiveResultSets...
Displaying data from ref cursor #1:
174, Abel, Ellen, 11-MAY-1996
Displaying data from ref cursor #3:
187, Cabrio, Anthony, 07-FEB-1999
Displaying data from ref cursor #1:
166, Ande, Sundar, 24-MAR-2000
Displaying data from ref cursor #3:
148, Cambrault, Gerald, 15-OCT-1999
本文介绍了如何在 .NET 应用程序中使用引用游标, 并介绍了游标的概念以及值得注意的某些重要的引用游标特性。 通过本文,您已经了解到
OracleRefCursor
类(与
OracleParameter、OracleDataReader、OracleDataAdapter
和
DataSet
类结合使用)可以轻松地用于将服务器中的数据读取到 .NET 代码中,你还从完整地完成了一个示例控制台应用程序,该程序包含了这些不同的内容。 完成本文中的步骤之后,您应该能够在 .NET 应用程序中实现引用游标。
Mark A. Williams
是《
.NET 专家 Oracle 编程
》(Apress,2004 年 11 月)的作者,目前在医疗诊断行业担任 Production DBA。 自从 7.0.1.16 版数据库推出以来,他便一直使用 Oracle 产品,他是一位 Oracle ACE,是 7、8、8
i
、9
i
和 10
g
版本数据库的 Oracle 认证数据库管理员专家。
将您的意见发送给我们