简介
Data Access Application Block 将访问 Microsoft SQL Server 数据库的性能和资源管理方面的最佳经验封装在一起。您可以很方便地在自己的 .NET 应用程序中将其作为构造块使用,从页减少了需要创建、测试和维护的自定义代码的数量。
Data Access Application Block 可以帮助您:
l 调用存储过程或 SQL 文本命令。
l 指定参数详细信息。(Parameters)
l 返回 SqlDataReader、DataSet 或 XmlReader 对象。
例如,在引用了 Data Access Application Block 的应用程序中,您可以简单地在一行代码中调用存储过程并生成 DataSet,如下所示:
[C#]
DataSet ds =
SqlHelper.ExecuteDataset(connectionString, CommandType.StoredProcedure,"getProductsByCategory", new SqlParameter("@CategoryID", categoryID));
一、基本用法
数据访问应用程序块的主类是SQLHelper,它是一个带有四个常用(和几个不太常用)方法的封装类,SqlHelper 类提供了一组静态方法,可以用来向 SQL Server 数据库发出许多各种不同类型的命令:
* ExecuteDataset会利用SQL查询生成一个DataSet对象。
* ExecuteReader会利用SQL查询生成一个SqlDataReader类的对象。
* ExecuteScalar会利用SQL查询生成一个单值对象,即结果集中第一行的第一条数据。
* ExecuteNonQuery此方法用于执行不返回任何行或值的命令。这些命令通常用于执行数据库更新,但也可用于返回存储过程的输出参数。
使用格式是:
[C#]
Execute* (SqlConnection connection, CommandType commandType,
string commandText)
Execute* (SqlConnection connection, CommandType commandType,
string commandText, params SqlParameter[] commandParameters)
Execute* (SqlConnection connection, string spName,
params object[] parameterValues)
Execute* (SqlConnection connection,
CommandType commandType, string commandText)
Execute* (SqlConnection connection,
CommandType commandType, string commandText,
params SqlParameter[] commandParameters)
Execute* (SqlConnection connection,
string spName, params object[] parameterValues)
如图1是Data Access Application Block的构成图。
现在让我们来仔细看每一个方法。
1、ExecuteDataset
ExecuteDataset会运行你的基本SELECT(选择)查询并生成一个DataSet,然后就能够被绑定到服务器对象上,或者被用来创建DataView(数据视图)。就和所有的方法一样,存在着很多重载,但是最常用的一个看起来像下面这样:
DataSetdataSet =
SqlHelper.ExecuteDataset(connString,"usp_GetStuffProcedure", parameter)
这里connString是连接字串;usp_GetStuffProcedure是储存过程名;parameter是传递给储存过程或储存过程返回来的参数。如用于SQL数据库的SqlParameters 对象是一个数组,用以存放储存过程中的变量或SQL命令的过滤条件参数。
在通常情况下,一般使用一个搜索参数把使用查询语句SELECT所得的查询结果填满DataSet。有了SqlParameters 数组后就可传递多参数,这些参数常是用作对数据表进行各种操作的过滤条件关键字。比如说传递三个参数作为搜索关键字,只需要像下面这样就行了:
DataSetdataSet = SqlHelper.ExecuteDataset(connString, "usp_SearchStuffProcedure", parameter1, parameter2, parameter3)
通常情况下只有使用储存过程,才使用Parameters(参数)。
2、ExecuteReader
ExecuteReader主要是用于查询语句(SELECT),它是为了提高运行性能而设置的。SqlDataReaders很类似于经典 ADO里的只能向前的只读记录集,它们对于填充ListBoxe控件和CheckBoxList控件很有用处。对ExecuteReader的调用看起来就像是一个ExecuteDataset。要记住,它需要命名空间为System.Data.SqlClient:
using System.Data.SqlClient;
SqlDataReadersqlDataReader = SqlHelper.ExecuteReader(connString,"usp_GetStuffProcedure", parameter);
3、ExecuteScalar
ExecuteScalar方法有多种用法,比如返回一个只带有一个值(例如记录总数COUNT)的SELECT查询。但是最常用的方法是在插入一条新的数据的语句(INSERT)。这是Transact SQL里相当常见的技巧,但是它需要使用存储过程里的一个进程,以确保数据插入后返回的数据是.NET最容易接受的格式:
INSERT (字段1, 字段2) VALUES (@parameter1, @parameter2)
SELECT CAST(@@Identity AS INTEGER)
为了让事情简单,这个值就要作为一个Object(对象)返回给.NET。为了让行ID以整数返回,你要使用 Convert.ToInt32()进行转换。
intnewRowId=Convert.ToInt;
(SqlHelper.ExecuteScalar(connString,"usp_InsertStuffProcedure",parameter1,parameter2));
4、ExecuteNonQuery
你要使用ExecuteNonQuery方法来运行其它所有的操作——UPDATE、DELETE,以及功能查询或者清理查询,这种操作不会返回任何值。它和其他的方法一样,将连接字符串、存储过程和参数作为自变量来处理。
SqlHelper.ExecuteNonQuery(connString,"usp_DeleteStuffProcedure",rowIdToDelete);
这里rowIdToDelete是操作参数。
如果在使用SqlHelper的命令时不是针对储存过程而是使用SQL语句,则要添加CommandType (命令类型格式)这一参数项。例如命令格式是字串型的则:
[C#]
Execute* (string connectionString, CommandType.Text, //命令格式声明
string commandText) // string commandText是具体的命令字串
Execute* (string connectionString, CommandType.Text,
string commandText,
params SqlParameter[] commandParameters)//使用参数缓存
Execute* (string connectionString, string spName, // string spName是命令字串名
params object[] parameterValues)//使用数据对象缓存
例如:
[C#]
DataSet ds = SqlHelper.ExecuteDataset(
"SERVER=DataServer;DATABASE=Northwind;INTEGRATED SECURITY=sspi;", _
//连接字串
CommandType.Text, "SELECT * FROM Products");//命令字串
二、通用指针
除了使用正确的方法来做正确的事之外,一些基本的最佳实践会让数据应用程序块在日常的编程工作中更加简单。从Web.config里获得你的连接字符串。
要注意在上面所有的例子里,只使用了一个叫做connString的字符串变量。这是因为在上面调用SqlHelper的代码里做了两件事。
第一,在Web.config里,创建了一个appSettings区,它可以通过System.Configuration类来访问:
<appSettings>
<add key="mainConnectionString" value="Data Source=myDb;Initial Catalog=database; user id=user1; password=pass1"/>
</appSettings>
第二,使用这个配置文件里的关键字对connString变量进行了初始化。要记住在组件里的命名空间是System.Configuration。
using System.Configuration;
string connString =ConfigurationSettings.AppSettings["mainConnectionString"];
三、使用存储过程
虽然任何人都可以使用SQL语句的方式查询,但效率低且程序编写也很麻烦。因为使用参数的不同,你就需要指定一个相应的命令类型。但存储过程是组件所默认的,使用存储过程的命令类型均为CommandType.StoredProcedure(命令类型.存储过程),因为各种操作语句就存放在存储过程中。
下面一句是使用了在程序中内嵌SQL语句的方法,为此,指定命令类型为:CommandType.Text。
SqlHelper.ExecuteNonQuery(connString, CommandType.Text, "DELETE FROM table1 WHERE rowId = " + rowId);
另外,使用内嵌SQL语句的做法除了语句编写繁琐外,更重要的是不安全,将自己暴露于潜在的SQL流量注入攻击之下。使用存储国过程就不再需要使用SQL语句了,只传递参数,而参数只有你自己才知道,这样安全性高。如果你准备使用DataSet,它的好处在于,它是一个可以拥有多个关系表(Table)的数据集。如把多个人的眼睛颜色和头发颜色保存在不同的数据表里,我们可以只使用一个存储过程来获取这些数据表的信息,创建到DataSet 里并生成多个Table,然后将Table绑定在ListBox等控件上显示出来。这个过程如下:
储存过程(简写):
--Table 0
SELECT 眼睛颜色, 头发颜色
FROM Employees
WHERE rowId = @RowId;
--Table 1
SELECT 眼睛颜色, 头发颜色
FROM HairColors
--Table 2
SELECT 眼睛颜色, 头发颜色
FROM EyeColors
程序代码:使用数据应用程序块来获取一个DataSet。
DataSetdataSet = SqlHelper.ExecuteDataset(connString, "usp_GetEmployeeColors", rowId)
然后,你就可以将ListBox绑定到第二和第三个表格上。下面是眼睛颜色的ListBox:
EyeColorListBox.DataSource = dataSet.Tables[2].DefaultView;//把DataSet中的Tables[2]的数据填充到控件EyeColorListBox
EyeColorListBox.DataTextField = "EyeColor";//其字段名为:EyeColor
EyeColorListBox.DataValueField = "EyeColorId";//字段值为:EyeColorId
EyeColorListBox.DataBind();//执行绑定
EyeColorListBox.Items.FindByValue(dataSet.Tables[0].Rows[0]["EyeColorId"].ToString()).Selected = true;
//选中数据集中的表1(Tables[0])中的第1行(Rows[0])中的EyeColorId数据单元。
四、使用缓存技术提高性能(使用 SqlHelperParameterCache 类管理参数)
我们知道,要对数据库进行各种操作都需要设置很多查询条件,来方便我们得到想要的数据。这些查询条件就是查询参数了。不论你采用SQL语句方式或者是存储过程方式来操作数据库,查询参数是必不可少的。例如你要对一个数据表字段进行大于”>”或小于”<”或等于”=”或大于等于”>=”等等的多种条件过滤查询时,你就必需要对每一种查询设置不同的参数,要对数据表进行条件查询的字段越多,参数就越多,为此SqlHelperParameterCache 类提供参数缓存功能,用以提高运行性能。该类由许多 Execute 方法在内部使用。数据访问客户端也可以直接使用它来缓存特定参数集。
SqlHelperParameterCache 类提供了三种可以用来管理参数的公共共享方法。它们是:
CacheParameterSet用于将 Parameters 对象存储到缓存中。
GetCachedParameterSet用于检索缓存中的Parameters。
GetSpParameterSet用于检索指定存储过程的相应参数,然后把检索的结果存入缓存(首先查询一次数据库,然后缓存结果)。
l 缓存和检索参数
通过使用 CacheParameterSet 方法,用以缓存 Parameter 对象。此方法通过将连接字符串和命令文本连接起来创建一个键,然后将参数数组存储在 Hashtable 中。
SqlParameter类用来储存 SQL命令(SqlCommand) 的参数(参数名称不区分大小写且多为储存过程的变量),也可以用来把它映射到 DataSet 的列。
要从缓存中检索参数,使用 GetCachedParameterSet 方法。此方法将返回一个 Parameter 对象数组,这些数组已使用缓存(与传递给该方法的连接字符串和命令文本相对应)中的参数的名称、值和数据类型等进行了初始化。
注意: 在索引参数集时,是通过字串比较来寻找匹配的。用作从 GetCachedParameterSet 中检索参数的字串必须与原来通过 CacheParameterSet 来存储这些参数字串格式要完全相同。格式不同的字串即使语义相同,也不会被认为是匹配的。
以下代码显示了如何使用 SqlHelperParameterCache 类来缓存和检索 Transact-SQL 语句的参数(使用内嵌SQL语句的方法)。
[C#]
1、初始化连接字符串和命令文本,它们将构成用来存储和检索参数的键
const string CONN_STRING =
"SERVER=(local); DATABASE=Northwind; INTEGRATED SECURITY=True;";//连接字串
string spName = "SELECT ProductName FROM Products " +
"WHERE Category=@Cat AND SupplierID = @Sup";//命令文本
这一步是建立命令参数。
2、缓存参数
SqlParameter[] paramsToStore = new SqlParameter[2];
//产生一个一维两单元的SqlParameter数组
paramsToStore[0] = New SqlParameter("@Cat", SqlDbType.Int);
//把变量@Cat存入SqlParameter的第一个单元中
paramsToStore[1] = New SqlParameter("@Sup", SqlDbType.Int);
//把变量@Sup存入SqlParameter的第二个单元中
SqlHelperParameterCache.CacheParameterSet(CONN_STRING, sql, paramsToStore);
//把括号中的参数缓存到SqlHelperParameterCache
这一步主要是把参数存入缓存中。
3、从缓存中把所需的参数检索出来
SqlParameter storedParams = new SqlParameter[2];
storedParams = SqlHelperParameterCache.GetCachedParameterSet(
CONN_STRING, sql);
storedParams(0).Value = 2;//检索使用值
storedParams(1).Value = 3; //检索使用值
这一步是根据检索使用值检索缓存中的SqlParameter数组看是否有匹配的参数
4、在命令中使用参数
DataSet ds;
ds = SqlHelper.ExecuteDataset(CONN_STRING,
CommandType.StoredProcedure,
sql, storedParams);
这一步主要是调用缓存中的参数执行数据表操作。
l 检索存储过程的参数
SqlHelperParameterCache 还提供了针对特定存储过程检索参数的方法。一个名为 GetSpParameterSet类的重载方法提供了此功能,它包含两种实现。该方法首先从缓存中检索特定存储过程的参数。如果这些参数尚未被缓存,则使用 SqlCommandBuilder 类的DeriveParameters方法(该方法是从 SqlCommand 指定的存储过程中检索参数信息,并存进指定的 SqlCommand 对象的 Parameters 集)对存储过程的内部进行检索,并将它们添加到缓存中,以便用于后续的检索请求。然后,为每个参数指定相应的参数设置,最后将这些参数以数组形式返回给客户端。以下代码显示了如何检索 Northwind 数据库中 SalesByCategory 存储过程的参数。
[C#]
1、初始化连接字符串和命令文本,它们将构成用来存储和检索参数的键
const string CONN_STRING =
"SERVER=(local); DATABASE=Northwind; INTEGRATED SECURITY=True;";//连接字串
string spName = "SalesByCategory";//储存过程名
2、检索参数
SqlParameter storedParams = new SqlParameter[2];//产生一个两单元的一维数组
storedParams = SqlHelperParameterCache.GetSpParameterSet(
CONN_STRING, spName);
//连接到指定的存储过程(spName)并在存储过程中检索参数
storedParams[0].Value = "Beverages";//给数组赋值
storedParams[1].Value = "1997";
3、在命令中使用参数
DataSet ds;
ds = SqlHelper.ExecuteDataset(CONN_STRING,
CommandType.StoredProcedure, spName, storedParams);
//把参数集storedParams传递给存储过程,执行查询命令
l 内部设计
SqlHelper 类还包含一些专用函数,用于管理参数和准备要执行的命令。不管客户端调用什么样的方法实现,所有命令都通过 SqlCommand 对象来执行。在 SqlCommand 对象能够被执行之前,所有参数都必须添加到 Parameters 集合中,并且必须正确设置 Connection、CommandType、CommandText 和 Transaction 属性。
SqlHelper 类中的专用函数主要用于提供一种一致的方式,以便向 SQL Server 数据库发出命令,而不考虑客户端应用程序如何调用类的重载方法。SqlHelper 类中的专用程序函数包括:
AttachParameters:该函数用于将所有必要的 SqlParameter 对象连接到正在运行的 SqlCommand。
AssignParameterValues:该函数用于为 SqlParameter 对象赋值。
PrepareCommand:该函数用于对命令的属性(如连接、事务环境等)进行初始化。
ExecuteReader:此专用 ExecuteReader 实现用于通过适当的 CommandBehavior 打开 SqlDataReader 对象,以便最有效地管理与阅读器关联的连接的有效期。
SqlHelperParameterCache 类实现详细信息
参数数组缓存在专用 Hashtable 中。从缓存中检索的参数进行内部复制,这样客户端应用程序能够更改参数值以及进行其他操作,而不会影响缓存的参数数组。专用共享函数 CloneParameters 可以实现此目的。
l 常见问题
如何使用 ExecuteDataset 返回包含多个表的数据集?
通过创建一个可以返回多个行集的存储过程(通过执行多个 SELECT 语句或者对其他存储过程进行嵌套调用),并使用 ExecuteDataset 方法执行该过程,您可以检索包含多个表的数据集。
例如,假设您的数据库包含以下两个存储过程。
CREATE PROCEDURE GetCategories
AS
SELECT * FROM Categories
GO
CREATE PROCEDURE GetProducts
AS
SELECT * FROM Products
GO
您可以创建一个主存储过程来对这些过程进行嵌套调用,如下面的代码示例所示。
CREATE PROCEDURE GetCategoriesAndProducts
AS
BEGIN
EXEC GetCategories
EXEC GetProducts
END
使用 ExecuteDataset 方法执行此主存储过程将返回一个 DateSet,其中包含两个表:一个表包含分类数据,另一个表包含产品数据。
注意: ExecuteDataset 方法不提供为返回的表指定自定义名称的方法。第一个表的编号始终为 0,名称为 Table,第二个表的编号为 1,名称为 Table1,依此类推。