Microsoft Enterprise Library中所带的Data Access Application Block(以下简称DAAB),对ADO.NET进行了一次封装,为数据库访问带来了极大的便利,尤其是与SQL Server配合使用,可谓得心应手。但是,其访问Oracle数据库,特别是使用Oracle的存储过程时,大家时常会遇到一些问题,例如:怎么通过Oracle的存储过程,来返回一个数据集?既然它们的访问方式有所不同,怎么才能让程序既适用于SQL Server又适用于Oracle?小弟有幸在项目中遇到了此种需求,并且找到了解决方案,拿出来与大家讨论。
说到Oracle中存储过程返回数据集与SQL有何不同,就要说到包的概念,因为SQL Server中不存在相对应的概念。网上有许多相关的文章,在此不再赘述。另一个不同点,就是SQL Server的存储过程中,执行一个SELECT语句,数据集会自动返回出来,而在Oracle中,需要通过一个指针来实现数据集的返回。来看具体的例子。
首先,我们来建立一个包,包头部分如下,它相当于C++中的头文件,用作声明之用,没有任何实现用的代码。
CREATE
OR
REPLACE
PACKAGE TEST.PKG_TEST
IS
TYPE MYCURSOR
IS
REF
CURSOR
;
PROCEDURE
GET_DEC_BILL_LIST(cur_OUT OUT MYCURSOR);
END
;
以上代码中,第一步,通过TYPE建立了一个指针类型MYCURSOR。第二步,声明了:此包中有一个存储过程GET_DEC_BILL_LIST,并且,这个存储过程中有一个cur_OUT的输出变量,其类型为MYCURSOR。
然后,我们来建立一个包体:
CREATE
OR
REPLACE
PACKAGE BODY TEST.PKG_TEST
IS
PROCEDURE
GET_DEC_BILL_LIST(cur_OUT OUT MYCURSOR)
AS
BEGIN
OPEN
cur_OUT
FOR
SELECT
*
FROM
ALL_TABLES
WHERE
OWNER
=
'
SYS
'
;
END
;
END
;
using
Microsoft.Practices.EnterpriseLibrary.Data;
//
Other Code here
//
private
void
button1_Click(
object
sender, EventArgs e)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
Database db = DatabaseFactory.CreateDatabase("LocalOracle"); //建立数据库对象
//全称:TEST用户下PKG_TEST包中的GET_DEC_BILL_LIST存储过程
string spName = "TEST.PKG_TEST.GET_DEC_BILL_LIST";
try
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
DbCommand cmd = db.GetStoredProcCommand(spName); //获取Command对象
DataSet ds;
ds = db.ExecuteDataSet(cmd); //执行SQL语句
dataGridView1.DataSource = ds.Tables[0].DefaultView;//绑定数据并且显示
}
catch (Exception ex)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
MessageBox.Show(ex.Message);
}
}
执行效果如图。
![](https://i-blog.csdnimg.cn/blog_migrate/8b16b8209bea1d3e65544ff42286b1ef.png)
继续往下看,精彩继续 ^_^
如果您照着示例做,但是运行时,收到一个错误提示,说参数类型不匹配,那么,答案在这里,这是DAAB中OracleDatabase.cs中的代码:
/**/
/// <devdoc>
/// This is a private method that will build the Oracle package name if your stored procedure
/// has proper prefix and postfix.
/// This functionality is include for
/// the portability of the architecture between SQL and Oracle datbase.
/// This method also adds the reference cursor to the command writer if not already added. This
/// is required for Oracle .NET managed data provider.
/// </devdoc>
private
void
PrepareCWRefCursor(DbCommand command)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
if (command == null) throw new ArgumentNullException("command");
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
if (CommandType.StoredProcedure == command.CommandType)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
// Check for ref. cursor in the command writer, if it does not exist, add a know reference cursor out
// of "cur_OUT"
if (QueryProcedureNeedsCursorParameter(command))
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
AddParameter(command as OracleCommand, RefCursorName, OracleType.Cursor, 0, ParameterDirection.Output, true, 0, 0, String.Empty, DataRowVersion.Default, Convert.DBNull);
}
}
}
AddParameter的第二个参数在前面的代码中有定义,为一个字符串常量:cur_OUT。所以,请修改您的存储过程,把输出指针的名称改为“cur_OUT”。
回头再看看前面示例中的C#代码,注意spName这个变量,用惯SQL Server的人一定会觉得这个名字怪怪的。能不能把代码改得像SQL Server中一样,只传递一个存储过程名称呢?呵呵,Microsoft在设计DAAB时已经考虑到了这个问题了,为了实现代码的可移植性,需要对app.config进行一下配置。在解决方案浏览器中右击app.config文本,选择Edit Enterprise Libraray Configuration。在配置好的Oracle Packages节点上右击,点击New、Oracle Package。如下图。
![](https://i-blog.csdnimg.cn/blog_migrate/fefe25e2e9c7690849eea5f02b0621cb.png)
然后,设置新建的Oracle包属性如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/8144b87a7a4c11ce5c117b68c4e326d8.png)
private
void
button1_Click(
object
sender, EventArgs e)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
Database db = DatabaseFactory.CreateDatabase("LocalOracle"); //建立数据库对象
//string spName = "TEST.PKG_TEST.GET_DEC_BILL_LIST";//全称
string spName="GET_DEC_BILL_LIST";//与SQL SERVER中一样,仅仅传入存储过程名称
try
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
DbCommand cmd = db.GetStoredProcCommand(spName); //获取Command对象
DataSet ds;
ds = db.ExecuteDataSet(cmd); //执行SQL语句
dataGridView1.DataSource = ds.Tables[0].DefaultView;//绑定数据并且显示
}
catch (Exception ex)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
{
MessageBox.Show(ex.Message);
}
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
}
说到Oracle中存储过程返回数据集与SQL有何不同,就要说到包的概念,因为SQL Server中不存在相对应的概念。网上有许多相关的文章,在此不再赘述。另一个不同点,就是SQL Server的存储过程中,执行一个SELECT语句,数据集会自动返回出来,而在Oracle中,需要通过一个指针来实现数据集的返回。来看具体的例子。
首先,我们来建立一个包,包头部分如下,它相当于C++中的头文件,用作声明之用,没有任何实现用的代码。
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
然后,我们来建立一个包体:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
以上代码中,实现了GET_DEC_BILL_LIST,其实质是打开了一个指针,其内容为SYS用户下的所有表的情况。这样子,数据库部分就Ready了。
接下来,我们就可以通过DAAB来调用这个存储过程了:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/8b16b8209bea1d3e65544ff42286b1ef.png)
继续往下看,精彩继续 ^_^
如果您照着示例做,但是运行时,收到一个错误提示,说参数类型不匹配,那么,答案在这里,这是DAAB中OracleDatabase.cs中的代码:
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
回头再看看前面示例中的C#代码,注意spName这个变量,用惯SQL Server的人一定会觉得这个名字怪怪的。能不能把代码改得像SQL Server中一样,只传递一个存储过程名称呢?呵呵,Microsoft在设计DAAB时已经考虑到了这个问题了,为了实现代码的可移植性,需要对app.config进行一下配置。在解决方案浏览器中右击app.config文本,选择Edit Enterprise Libraray Configuration。在配置好的Oracle Packages节点上右击,点击New、Oracle Package。如下图。
![](https://i-blog.csdnimg.cn/blog_migrate/fefe25e2e9c7690849eea5f02b0621cb.png)
然后,设置新建的Oracle包属性如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/8144b87a7a4c11ce5c117b68c4e326d8.png)
只要存储过程前缀与设置的相同,DAAB执行存储过程时,便会自动添加前缀,于是示例代码便可以修改如下。
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/3112b7b6526db5bc83e275260ae60525.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f2671b7f42ce505d9bf55a7a0ca257fb.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/eec4c0236afc26744c9c4e910bc34958.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
总结一下,通过DAAB,我们实现了在C#中,调用ORACLE的存储过程返回一个数据集,并且,通过简单的配置,把调用方法与SQL统一了起来。