.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
分享到:
相关推荐
在.NET框架中,调用存储过程是一个常见的任务,无论是在ASP.NET、C#还是C++中。为了实现统一的调用方法,我们可以构建一个抽象层,使得开发者只需要提供存储过程名称和参数值,就能自动处理参数创建、设置及执行存储...
在VB.NET编程语言中,数据安全性和隐私保护是软件开发过程中不可或缺的一部分。加密技术被广泛应用于各种应用场景中,比如保护用户的登录凭据、敏感信息等。本文将详细介绍如何在VB.NET中实现加密功能,并提供一个...
**存储过程**:讲解如何使用 LINQ to SQL 调用数据库中的存储过程。 6. **探究特性**:探讨 LINQ to SQL 中的一些高级特性,如延迟加载等。 7. **并发与事务**:介绍如何处理并发问题及如何使用 LINQ to SQL 实现...
`SQLHelper`类是.NET框架中用于封装对数据库进行各种操作的方法集合,它的设计目的是为了简化和统一数据库操作的代码,提高代码的可读性和可维护性。通过使用`SQLHelper`类,开发者可以避免编写大量重复的数据库连接...
在探讨ASP.NET编程语言的学习过程中,掌握相关的英语词汇是至关重要的。这些词汇不仅仅是技术术语,它们构成了理解ASP.NET框架、其特性和编程实践的基础。以下是从给定文档中提炼的关键知识点,涵盖了从抽象概念到...
在.NET框架中,生成和解析二维码以及调用摄像头识别二维码是一项常见的任务,特别是在移动应用、物联网设备连接或者数据交换场景中。本项目源码主要基于C#编程语言,提供了完整的功能实现,帮助开发者快速集成二维码...
3. 表单提交:在ASP.NET Web Form中,使用`<asp:TextBox>`控件收集用户信息,然后在服务器端处理表单提交,调用 Membership API 创建新用户。 4. 用户状态管理:在注册成功后,可以使用ASP.NET的Session或Cookie...
- **CLS**(Common Language Specification): 公共语言规范,定义了.NET Framework中不同语言之间相互调用的标准。 - **CLR**(Common Language Runtime): 公共语言运行时,负责管理代码的执行环境。 这三个概念...
10. **LINQ(Language Integrated Query)**: LINQ是VB.NET的一个强大特性,它允许开发者以统一的方式查询各种数据源,如数据库、XML文档或内存中的集合。 11. **异步编程**: VB.NET引入了async/await关键字,使得...
另一方面,DataAccess Objects则封装了数据访问过程,允许应用程序以统一的接口访问不同的数据存储机制,从而隐藏了持久化层的具体实现细节。 #### 三、IBatisNet的实践准备与开发流程 ##### 准备工作 使用...
.NET框架是微软推出的一种全新的编程模型,旨在提供一个统一的面向对象环境,它与C++的结合使得开发者能够在C++中利用.NET框架的强大功能。在.NET框架中,开发者可以享受到语言无关性,这意味着不同编程语言编写的...
在VB.NET中,数据通过变量存储,类型包括基本类型(如整数、浮点数、字符串)和复杂类型(如数组、结构)。 **3.2 变量** 变量是存储数据的容器,其值可以在程序执行过程中改变。VB.NET支持声明和初始化变量,例如...
9. **LINQ(Language Integrated Query)**:VB.NET的LINQ允许开发者以一种统一且简洁的方式查询各种数据源,如数据库、XML文档或内存中的对象集合。 10. **窗体与控件**:对于GUI编程,VB.NET提供了丰富的窗体...
ASP.NET中还提供了控件状态属性作为在服务器往返过程中存储自定义控件中的数据的方法。在页面控件中,如果有多个自定义控件使用多个不同的控件来显示不同的数据结构,为了让这些页面控件能够在在页面上协调的工作,...
标题中的".NET通用数据库访问类(支持存储过程)"是指一种.NET框架下的编程工具,它提供了一个统一的接口,使得开发者可以方便地访问多种类型的数据库,包括SQLServer、Oracle、MySQL、SQLite、ACCESS以及DB2。...
值类型存储在栈中,而引用类型存储在堆中。了解这两种类型的区别对于有效地使用.NET至关重要。 #### 五、对象的生命周期 对象从创建到销毁的过程被称为对象的生命周期。在.NET中,对象的生命周期主要包括以下几个...
4. 显示报表:在ASP.NET页面上放置报表控件,并在适当的位置调用Render方法将报表渲染出来。 三、实例解析 压缩包中的"图形报表"可能包含多个示例项目,每个项目可能演示了不同类型的图形报表或者不同的数据处理...
在邮件处理过程中,这些辅助函数可能会用于格式化邮件内容、检查参数合法性或者捕获并处理可能出现的异常。 `PSQL.cs`可能涉及到与SQL数据库的交互,这在需要将邮件信息存储在关系数据库中时会用到。例如,可能有一...
面向对象编程(Object-Oriented Programming,简称OOP)是软件开发中的一种核心概念,它在.Net框架中得到了广泛的应用。.Net OOP学习教程涵盖了该领域的基础与进阶知识,帮助开发者理解并掌握如何利用C#语言进行高效...
- **CTS(Common Type System)**:是.NET Framework的类型系统,确保所有.NET语言之间具有互操作性,统一了类型表示和类型检查。 - **CLS(Common Language Specification)**:是.NET Framework的一部分,定义了...