在.NET中访问Oracle的方式有很多,配置成ODBC、OLEDB、OracleClient,当然配置成OracleClient是最高效的,还有一种方式是通过Enterprise Library 来访问,EL使用反射原理,最后还是用的OracleClient。
用OracleClient访问Oracle存储比较简单,原因很简单:
System.Data.OracleClient 中所有方法都是专门对于Oracle来写的,充分体现了Oracle的特点,使用起来非常简单,在MSDN中有比较详细的例子。
在大量最佳实践的基础上,微软社区上出现了Enterprise Library这个东东,它在.NET的各个数据访问提供程序基础上用类工厂的原理进行动态组装,可以使程序动态配置而不用编译源代码。
DAAB在SQL Server上使用起来相当方便,但是用在Oracle上有些技巧,这是Oracle和SQL Server有些不同点造成的,在Oracle中过程返回一个结果集的时候与SQL Server做法有很多的不同,我的上一篇文章说明这点。
1、创建一下过程:
读取信息
1/**//* Formatted on 2006/11/22 16:49 (Formatter Plus v4.8.7) */
2CREATE OR REPLACE PACKAGE pkgentlib_slope
3AS
4 TYPE t_cursor IS REF CURSOR;
5
6 PROCEDURE entlib_slope (cur_OUT OUT t_cursor);
7END pkgentlib_slope;
8
9CREATE OR REPLACE PACKAGE BODY pkgentlib_slope
10AS
11 PROCEDURE entlib_slope (cur_OUT OUT t_cursor)
12 IS
13 BEGIN
14 OPEN cur_OUT FOR
15 SELECT *
16 FROM side_slope;
17 END entlib_slope;
18END pkgentlib_slope;
19
2、执行一下C#代码就可以将SP中的结果集返回
1DbCommand dbCmd = db.GetStoredProcCommand("pkgENTLIB_slope.ENTLIB_slope");
2return db.ExecuteDataSet(dbCmd);
说明:以上SP代码若是将"cur_OUT"改成其他的C#代码执行报错,为什么?
看看EL中的源代码你就会清楚:
Executes a command and returns the results in a new
1/**//// <summary>
2 /// <para>Executes a command and returns the results in a new <see cref="DataSet"/>.</para>
3 /// </summary>
4 /// <param name="command"><para>The command to execute to fill the <see cref="DataSet"/></para></param>
5 /// <returns><para>A <see cref="DataSet"/> filed with records and, if necessary, schema.</para></returns>
6 /// <exception cref="ArgumentNullException">
7 /// <para><paramref name="command"/> can not be <see langword="null"/> (Nothing in Visual Basic).</para>
8 /// </exception>
9 public override DataSet ExecuteDataSet(DbCommand command)
10 {
11 PrepareCWRefCursor(command);
12 return base.ExecuteDataSet(command);
13 }
PrepareCWRefCursor
1/**//// <devdoc>
2 /// This is a private method that will build the Oracle package name if your stored procedure
3 /// has proper prefix and postfix.
4 /// This functionality is include for
5 /// the portability of the architecture between SQL and Oracle datbase.
6 /// This method also adds the reference cursor to the command writer if not already added. This
7 /// is required for Oracle .NET managed data provider.
8 /// </devdoc>
9 private void PrepareCWRefCursor(DbCommand command)
10 {
11 if (command == null) throw new ArgumentNullException("command");
12
13 if (CommandType.StoredProcedure == command.CommandType)
14 {
15 // Check for ref. cursor in the command writer, if it does not exist, add a know reference cursor out
16 // of "cur_OUT"
17 if (QueryProcedureNeedsCursorParameter(command))
18 {
19 AddParameter(command as OracleCommand, RefCursorName, OracleType.Cursor, 0, ParameterDirection.Output, true, 0, 0, String.Empty, DataRowVersion.Default, Convert.DBNull);
20 }
21 }
22 }
QueryProcedureNeedsCursorParameter
1private static bool QueryProcedureNeedsCursorParameter(DbCommand command)
2 {
3 foreach (OracleParameter parameter in command.Parameters)
4 {
5 if (parameter.OracleType == OracleType.Cursor)
6 {
7 return false;
8 }
9 }
10 return true;
11 }
EL将cur_OUT写死在代码中了,判断SP中是否有Cursor类型的参数,有则对其赋值,本人写的代码刚好与之吻合(此处的吻合不是碰巧的!! ^_^),而且刚好只有一个Cursor类型的,所以运行通过了。
写死带来一个问题,若是要一次查询返回多个结果集,一个cur_OUT肯定解决不了问题的,此时得退一步要将DbCommand换成OracleCommand就可以解决问题了,OracleCommand对象的Parameters可以用Add添加 OracleType.Cursor类型的参数到存储过程中,再用DataBase.ExecuteDataSet(OracleCommand),就可以返回结果集,这时返回的结果集可以多个,问题得以解决!!!
不知道高手们有什么其他的高见,请明示!