.NET中统一的存储过程调用方法(收藏)

.NET中统一的存储过程调用方法(收藏)

摘要:在一个项目的开发中,经常会调用数据库中的存储过程。可是,几乎所有存储过程的调用都是同一个模式,主要区别就在于创建的每个参数类型、值等不一样。那么,能不能实现通过一个函数(或者类)调用所有的存储过程呢?本文在利用数据库提供的系统表原理上,实现了统一调用的方法,该方法只需要提供要调用的存储过程名,以及调用时提供具体的参数值就可实现任何存储过程的调用。

Abstract: We have to call stored procedures of database systems during a development of a project. However, calling a stored procedures are almost the same, the main difference is the difference between parameters’ type or value etc. Can we call any stored procedures through a function (or a class)? Based on the system tables provided by database systems, We wrote a class to call any stored procedures in this article. To call a stored procedure, the only parameters you provide are the name of the stored procedure and the value of all parameters of the stored procedure.
1. 引言
在各种系统开发中,使用存储过程是一个良好的习惯,不仅可以带来临时表、函数、游标等特性,而且调试、升级、维护都变得方便。在存储过程中能够把数据经过处理再返回,这样能够对数据提供更多的分析和控制。
在存储过程的调用中,我们发现存储过程的调用都几乎是如下的模式:
1 .声明 SqlConnection
2 .声明 SqlCommand ,并且设置其 Connection 属性为刚声明的 SqlConnection 实例,设置 CommandName 为存储过程名, CommandType 为存储过程。
3 .往刚声明的 SqlCommand 实例的 Parameters 集合中添加所有的存储过程调用需要的参数
4 .呼叫 SqlCommand 的 ExecuteReader() 方法来得到存储过程的返回行集
4 .声明 SqlDataAdapter 和 DataSet ,设置 SqlDataAdapter 的 SelectCommand 属性为 3 中声明的实例,再调用其 Fill 方法来把返回的行集填充到 DataSet 中
5 .关闭 SqlConnection 对象
6 .释放声明的各对象实例
(说明: 4 指的是两种数据提取方法)
在这个调用过程中,我们发现几乎所有的存储过程调用都是这个模式,之间的区别就在第 2 步中的存储过程名不同和第 3 步中各个存储过程调用使用的参数是不一样的,他们有参数名字、方向、数据类型、长度等的区别。
那么,有没有一种方法可以实现所有的存储过程调用?即只需要提供存储过程名,然后把参数值传入调用方法即可实现存储过程的调用,再用某些数据结构来保存返回的行集、传出参数值、过程返回值。经过研究 SQL Server 的系统表,我们发现这个想法是切实可行的。
2 .系统表与信息结构视图
SQL Server 等关系型数据库都将元数据以某种方式保存在数据库中,在 SQL Server 中就是系统数据库和系统表。安装 SQL Server 后会自动生成四个系统数据库: master, model, msdb 与 tempdb 。 master 数据库是 SQL Server 中所有系统级信息的仓库。登录帐号、配置设置、系统存储过程和其他数据库的存在性都记录在 master 数据库中。 msdb 数据库保存 SQL Server Agent 的信息。定义作业、操作员和警报时,他们存放在 msdb 中。 model 是个模框,用于所有用户生成的数据库。生成新数据库时,将 model 复制,建立所要的对象。 tempdb 保存 SQL Server 中的临时对象。显示生成的临时表和临时存储过程以及系统生成的临时对象都利用 tempdb 。 [1]
而且每个数据库中都有自己的系统表。这些系统表被用来保存配置和对象信息。从这些系统表中,我们就可以得到每个存储过程的所有参数的信息。 syscolumns 表中就保存了这些信息。其中有参数名、类型、长度、方向等需要用到我们方法中的信息。
不过,系统表中的字段会随着 SQL Server 版本的变化而变化。比如 syscolumns 中的 type 和 xtype 就是这样的一个变化例子,他们都保存了类型的信息。要让我们的方法适应 SQL Server 的版本变化要求,就要用到信息结构视图。
ANSI-92 将信息结构视图定义为一组提供系统数据的视图。通过利用该视图,可以将实际系统表从应用程序中隐藏起来。系统表的改变就不会影响到应用程序,这样应用程序就可以独立于数据库厂家和版本。 [1]
ANSI-92 和 SQL Server 支持用三段命名结构引用本地服务器上的对象。 ANSI-92 术语称为 catalog.schema.object ,而 SQL Server 称为 database.owner.object 。 [1] 比如我们要找到所有存储过程的所有参数信息,就可以用:
select * from INFORMATION_SCHEMA.PARAMETERS
如果要找到某个存储过程的所有参数信息,就是:
select * from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME =’Proc1’
有了信息结构视图,我们的问题就解决了一大半了。下面我们看如何在 .NET 中实现我们的方法。
3 .实现方法
实现的重点就放在如何根据存储过程名来得到它的所有的参数信息,再根据这些参数信息自动的创建各个参数。为了让这些动作自动化,声明 SqlConnection 、 SqlCommand 、 SqlParameter 的过程,创建各个 SqlParameter 的过程对用户来说都应该不可见。用户唯一需要提供的就是存储过程的名字,然后就是在调用的时候提供各个参数,甚至连他们的类型都不需要提供。
3 1 获得和创建存储过程的参数
如何获得并且创建要调用的存储过程的参数是一个重点,通过信息结构视图我们可以自动的实现这个步骤。
// 获得和创建存储过程的参数
private void GetProcedureParameter(params object[] parameters)
{
 SqlCommand myCommand2 = new SqlCommand();
 myCommand2.Connection = this.myConnection;
 myCommand2.CommandText = "select * from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME='" +this.ProcedureName+ "' order by ORDINAL_POSITION";
 SqlDataReader reader = null;
 reader = myCommand2.ExecuteReader();
  // 创建返回参数
  myParameter = new SqlParameter();
  myParameter.ParameterName = "@Value";
  myParameter.SqlDbType = SqlDbType.Int;
  myParameter.Direction = ParameterDirection.ReturnValue;
  myCommand.Parameters.Add(myParameter);
  int i = 0;
  // 创建各个参数,在这个地方可以自动的创建SqlParameter的类型,值,方向等属性
  while(reader.Read())
  {
  myParameter = new SqlParameter();
  myParameter.ParameterName = reader["PARAMETER_NAME"].ToString();
  myParameter.Direction = reader["PARAMETER_MODE"].ToString()=="IN"?ParameterDirection.Input:ParameterDirection.Output;
  switch(reader["DATA_TYPE"].ToString())
  {
   case "int" :
   if(myParameter.Direction == ParameterDirection.Input)
    myParameter.Value = (int)parameters[i];
   myParameter.SqlDbType = SqlDbType.Int;
 
   break;
   //...省略了很多具体的类型处理
   default : break;
  }
  i++;
  myCommand.Parameters.Add(myParameter);
  }
}
3 2 返回结果数据集、返回值、传出参数集
创建好存储过程的参数之后,我们就可以调用这个存储过程了。由于在 .NET 中,常用的返回结果集的类为 SqlDataReader 和 DataSet ,而 SqlDataReader 必须在保持连接的状态下才可以使用, DataSet 却不需要。在我们的实现中,连接应该在调用之后就断开,因此采用 DataSet 来保存返回结果集。
public SqlResult Call(params object[] parameters)
{
 // SqlResult是自己定义的用于保存结果数据集、返回值、传出参数集的类
 SqlResult result = new SqlResult();
 // 根据需要定义自己的连接字符串
 myConnection= new SqlConnection(ConnectionString);
 myCommand = new SqlCommand(this.ProcedureName, myConnection);
 myCommand.CommandType = CommandType.StoredProcedure;
 SqlDataAdapter myAdapter = new SqlDataAdapter(myCommand);
 myConnection.Open();
 // 获得和创建存储过程的参数,并且设置好值
 GetProcedureParameter(parameters);
 myAdapter.Fill(result.dataSet, "Table");
 
 // 获得存储过程的传出参数值和名字对,保存在一个Hashtable中
 GetOutputValue(result);
 // 在这里释放各种资源,断开连接
 myAdapter.Dispose();
 myCommand.Dispose();
 myConnection.Close();
 myConnection.Dispose();
 return result;
}
4. 进一步工作
虽然我们在这里的实现是针对 SQL Server 数据库,但是对于任何提供了信息结构视图,符合 ANSI-92 标准,或者是提供了元数据的数据库都可以使用这种方法来实现。我们把它封装成一个 SqlProcedure 类,在需要的时候可以很简单的就调用了存储过程,减少了大量基本上是重复的代码工作。
为了让 SqlProcedure 类支持更过的数据类型,在 GetProcedureParameter() 方法中需要根据自己的需要来分析各个参数的类型、方向、长度、默认值等信息,然后来创建这个参数。基本上任何类型都是能够实现的,甚至连 image 类型都可以采用这种方式创建。这样这个类就可以很通用,在任何项目中都可以发挥作用。
作者简介:
刘志波( 1979- ),男,湖南新化人,硕士,主要研究方向:神经网络与模式识别,办公自动化信息系统
email:jasper_liu@msn.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值