ADO.NET基础

ADO.NET基础

相当多的计算机应用,包括桌面和Web应用,都是数据驱动的(data-driven)。这些应用特别关心获取、显示和修改数据。

获取和处理数据看起来是很直截了当的工作,但在过去十年里,应用使用数据的方法反复改变了多次。开发人员从简单的使用本地数据的客户端应用转移到了基于专业集中化的数据库的分布是系统上。同时,数据访问技术得到了发展。如果你有使用微软语言的经验,你可能已经听过(甚至用过)数据访问技术的一些名词,包括ODBC,DAO,RDO,RDSADO

.NET框架有它自己的数据访问技术---ADO.NETADO.NET包含了可管理的类。这些类允许.NET应用连接到数据源(通常是关系数据库),执行命令,并且管理未连接的数据。ADO.NET的一点神奇之处是它允许你为Web应用写的数据访问代码与C/S桌面应用的代码差不多的方式,甚至与0连接到本地数据库的单用户应用一样的。

本章描述了ADO.NET的结构和ADO.NET数据提供者。你会学习到ADO.NET的基础,如打开连接,执行SQL语句或存储过程,获得查询的结果。你也会学习如何防止SQL注入攻击和使用事务。

 

ADO.NET.NET2.0里的变化

如果你已经习惯了.NET1.1编程,你会想知道在最新的ADO.NET中有哪些亲折内容。ASP.NET应用最大的变化是数据绑定模型(在第9章和第10章描述). 数据绑定使你能够在编写数据显示程序时, 减少大量代码, 你甚至可以不写一行代码.(如果你愿意面对使用页面进行支付时具有很少的灵活性, 优化相当困难的局面的话).

尽管有了新的数据绑定模型, ADO.NET的底层变化并不大。多数变化是内部的(如DataSet串行格式更加浓缩,占用更小的内存),或者对那些在未来的Web应用中用处不大的装饰性内容进行了修改(如用于在两个数据库服务器间快速传整整个表的新的SQL批量拷贝特征)。在.NET2.0 Beta版中,一些特征被去掉了(如为了获得查询的部分结果的内建页支持,为关系映射而开发的ObjectSpaces系统,使Dataset-to-XML会话功能更强的xmlAdapter,等等)。这些功能可以在分离的工具或者后续版本的.net中找到,但现在的程序员还得不得到这便利。

那么,那到底给我们带来了什么呢?这里列举了一些真正吸引人的变化:

提供者工厂(Provider factories:通用数据访问代码(也就是写一次就能应用于多个不同数据库的代码)之梦在.NET2.0中获得了巨大的飞跃。这个飞跃来自于提供者工厂。提供者工厂是一个新的组件,它能够快速地创建强类型的连接(connection,命令(command)和数据适配器(DataAdapter)对象。在这一章中你会了解到它。

改变通知(Change notification):为了创建确实可扩展的Web应用,你需要缓存从数据库获得的数据,使它能够重用,而不需要每次都连接到数据源。但是,缓存的引入可能会导致过期信息(out-of-date information),ADO.NET包含了新的改变通知特征,以便于数据库的记录更新后可以自动移除缓存的数据。这个内容将在第11章中介绍。

连接统计(Connection statistics):这是一个小小的点缀,但是SqlConnection对象的新的连接跟踪特征将帮助你描述不同数据访问策略。本章中将对此进行介绍。

SQL Server2005SQL Server2005引入了一整套新特征,ASP.NET2.0对这些新特征提供了无缝支持。这些特征包括基于.NET类的用户自定义数据类型,也可用在.NET语言编写存储过程语句。关于这些特征的更多信息可以参考专门的SQL Server2005书籍,比如《A First Look at Microsoft SQL Server 2005 for Developers(Addison-Wesley, 2004) or Pro SQL Server 2005 Assemblies (Apress, 2005).

 

ADO.NET结构

ADO.NET使用了多层结构,这个结构围绕几个关键概念进行,比如Connection, Command, DataSet对象。但是,AD.NET结构与经典的ADO还是有些区别的。

ADOADO.NET的一个关键区别是怎样面对不同数据源的挑战。在ADO中,程序员通常使一个通用的对象集,而不需要下层的数据源是什么。例如,如果你想从Oracle数据库中获取一条记录,你使用与在SQL Server中完成相同任务的同样的Connection类。这种情况在ADO.NET中不会发生,因为后者使用了数据提供者(data provider)模型。

 

ADO.NET数据提供者

数据提供者(data provider)是一个ADO.NET类集,它允许你访问特定的数据库,执行SQL命令,获取数据。本质上,数据提供者是应用和数据源的桥梁。

这些类包装数据提供者包含如下内容:

Connection: 你使用这个对象去建立到数据源的连接。

Command: 你使用这个对象执行SQL命令和存储过程。

DataReader: 这个对象提供从查询中快速地、前向地(forward-only)、只读地(read-only)访问数据。

DataAdapter: 这个对象执行两项任务。第一项,你可以使用它来将从数据源获取的特定信息填充DataSetDataSet是一个非连接的表和关系的集合)。第二项,你可以使用它将修改后的内容应用到数据源。

ADO.NET并没有包含通用的的数据提供对象。相反,它为不同类型的数据源提供了不同的数据提供者。每个数据提供者都有为优化特定的关系数据库管理系统(RDBMS)的Connection, Command, DataReaderDataAdapter类的特定的实现。例如,如果你想创建到SQL Server数据库的连接,你需要使用SqlConnection连接类。

ADO.NET提供者模型的一个基本的思想是可扩展性。换句说话,程序员能够为私有的数据源创建自己的提供者。事实上,可以找到大量的概念示例来帮助你了解如何简便地创建自定义的ADO.NET提供者,以便于包装非关系的数据存储,如文件系统或者目录服务。一些第三方开发者有自定义的.NET提供者出售。

.NET框架由下面四个极小的提供者集组合而成。

SQL Server provider:提供对SQL Server数据库的优化访问(不低于7.0版)。

OLE DB provider:提供具有OLE DB驱动的任何数据源的访问,包括SQL Server 7.0以前的版本。

Oracel provider:提供对Oracle数据库的优化访问(不低于8i版本)。

ODBC provider:提供对具有ODBC驱动的任何数据源的访问。

7-1显示了ADO.NET提供者模型的各个层次

7-1 ADO.NET结构

选择提供者时,你应该首先选择本地的.NET提供者来为你的数据源进行自定义。如果找不到本地的提供者,你可以使用OLD DB提供者,只要具备为了访问数据源的OLD DB驱动。OLE DB技术在很多年前就已经成为ADO的一部分了,因此大多数数据源提供OLE DB驱动(包括SQL Server, Access, MySQL等等)。在很少的情冲下,你找不到专门的.NET提供者和OLE DB驱动器,那么你可以退回去使用ODBC提供者,它连接到ODBC驱动器进行工作。

提示:在同时能够使用OLE DB提供者和为某种数据源专门提供的提供者时,你应该选择后者,因为后者是为其专门进行了优化的,执行得最好。

 

ADO.NET标准化

粗看起来,ADO.NET提供的模型是零散的,因为它没有包含一个通过的对象集,来处理多种不同类型的数据库。因此,如果你从使用的RDBMS改变成其它数据库,你需要使用不同的类集,修改数据访问代码。

尽管不同的.NET数据提供者使用不同的类,但所有提供者都是采用同一方法进行标准化的。说得更明确一点,就是每个提供者都是基于相同的基类和接口集。例如,每个连接对象都执行IDbConnection接口,这些接口定义了核心的方法,如Open()Close()。这个标准化保证每个连接类以同样的方式工作,并且向用户提供的核心属性和方法集是一样的。

在可视的界面之后,不同的提供者使用完全不同的底层调用和API。举个例来说,SQL Server提供者使用私有的TDSTabular Data Stream)协议来与服务器通信。这个模型的好处并不是显而易见的,但它们很重要:

因为每个提供者使用相同的接口和基类,你可以编写通用的数据访问代码(只需一点点的努力),而不是需要针对具体的提供者类编写代码。你将在“Provider-Agnostic Code”一节中看到这个技术所起的作用。

由于每个提供者的实现是完全分离的,它可以使用私有的优化措施(这与ADO模型不同。在ADO中,每个数据库调用需要在到达底层数据库驱动前要使用通过的层来进行过滤)。另外,自定义提供者能够添加非标准的功能,扩展在其它提供者中的不足(如SQL Server能够执行XML查询)。

ADO.NET也有另一个标准的层:DataSetDataSet是一个能满足所有要求的数据容器,这些数据来自于一个数据源的一个或多个表。DataSet非常通用,换句话说,自定义提供者不需要定义DataSet类的自定义版本。无论你使用哪种数据提供者,你都能够以同样的方法提取数据和将数据放入未连接的DataSet。这样就使得数据获取代码和数据处理代码分离开来。如果你改变了底层的数据库,你只需要改变数据获取代码,但如果你使用的DataSet和你的信息具有相同的结构,你就不需要改变数据处理的方法。

提示:下一章将对DataSet进行详细介绍,你将学到如何使用ADO.NET执行直接的、基于连接的访问的基本原理。

 

SQL Server 2005

ADO.NET提供少量支持SQL Server 2005的功能,这些功能包括:

多活动结果集(MARSmultiple active result sets):这允许你同时有多个活动的查询。例如,你可以查询顾客列表,在不关闭查询的同时查询订单列表。这个技术有时很有用,但它要求你能够避免额外的过载。

用户自定义数据类型(User-defined data types):使用.NET编码,你可以自定义类,并且将类的实例直接存储在数据库的一列里。这会使检查一行里的内个字段,并且手工创建应用中要使用的相应的数据对象的工作大为减少。

被管理的存储过程:SQL Server 2005能够以CLR为宿主,这样就可以使用纯C#代码在数据库中编写存储过程。

SQL通知(SQL nitificatons):当数据库中指定的改变发生时,使用通知可以编写相应的响应代码。在ASP.NET中,这个功能通常用于数据库中的一条或多条记录更新时,使缓存的数据失效。这仅仅是SQL Server 2005的功能,但同时也支持SQL Server 7 SQL Server 2000,当然,这需要使用不同的机制。

事务隔离快照(Snapshop transaction isolation):这是一个新的事务层次,它可以使你增强并发水平。它允许事务查看稍有点早的数据版本,尽管这些数据已经被别的事务更新了。

本书的大部分内容都集中关注与关系数据库相关的程序设计技术。当然,由于SQL通知在ASP.NET中的应用很广,在第11章也对SQL通知进行了详细讲述。在更早的SQL Server版本中,它们通过别的技术,也提供了支持。本章简要地涉及了隔离快照。针对SQL Server 2005的其它更多功能,你可以查阅 A First Look at Microsoft SQL Server 2005 for Developers(Addison–Wesley,2004) Pro SQL Server 2005 Assemblies(Apress, 2005).

 

ADO.NET基础类

ADO.NET有两种对象:基于连接的(connection-based)和基于内容的(content-based)。

基于连接的对象Connection-based objects):有一些数据提供者,如Connection, Command, DataAdapterDataReader。它们执行SQL语句,连接到数据库,或者填充DataSet。基于连接的对象是针对特定的数据源开发的。

基于内容的对象Content-based objects):这些对象是数据包。它们包含DataSetDataColumn, DataRow, DataRelation,以及其它的几个对象。它们与数据源的类型相独立,在System.Data命名空间定义。

本章的余下部分里,你将学习到ADO.NET的第一个层次,也就是基于连接的对象,包括Connection, Command, DataReader。你根本不需要了解更高层次的DataAdapter,因为DataAdapter被设计来用于DataSet,这将在第8章讨论(本质上,DataAdapter是一组相关的通用对象,这些对象使DataSet和数据源进行同步)。

.NET类被组合到几个命名空间中。每个提供者有它们自己的命名空间,通用的类,如DataSet存储在System.Data命名空间中,表7-1描述了命名空间:

命名空间

描述

System.Data

包含关键数据容器类,它们规范了列(Columns),关系(relations),表(tables),数据集(dataset),行(rows),视图(views)和约束(constraints)。另外, 包含了基于连接的数据对象的实现的关键接口。

System.Data.Common

包含基础的,绝大多数是抽象的类。实现了来自于System.Data的一些接口,并且定义了ADO.NET的核心功能。数据提供者从这些类继续并且创建它们自己特定的版本。

System.Data.OleDb

包含了常用于连接到OLE DB的提供者,包括OleDbConmmand, OleDbConnection, OleDbDataAdapter。这些类支持大多数的OLE DB提供者,要求OLE DB 2.5版本接口的除外。

System.Data.SqlClient

包含了连接到SQL Server数据库的类,包括SqlDbCommand, SqlDbConnectionSqlDBDataAdpater。这些类优化了连接到SQL ServerTDS接口。

System.Data.OracleClient

包含了连接到Oracle数据库的类(不低于8.1.7版本),包括:OracleCommand, OracleConnection, OracleDataAdapter。这些类使用优化的Oracle调用接口(OCI, Call Interface)。

System.Data.Odbc

包含了要求连接到多数ODBC驱动的类。这些类包括OdbcCommand, OdbcConnectionOdbcDataAdapterODBC驱动适用于所有的数据源,通过控制面版中的数据源图标进行配置。

System.Data.SqlTypes

包含了匹配SQL Server数据库的本地数据的结构。这些类并不是必需的,但是提供了使用标准.NET数据类型的一种方法,以便于自动转换。

7-1  ADO.NET命名空间

 

Connection

Connection类允许你建立到数据源的连接,以便于与之进行交互。在你做任何事情之前(包括获取、删除、插入、更新数据),你需要建立连接。

Connection的核心属性和方法由IdbConnection接口接定,这些接口由所有Connection类实现。

 

连接串(Connection Strings

当你创建一个Connection对象时,你需要提供一个Connection串。连接串是分号分隔的名字/值(name/value)设置序列。这些设置的顺序和大小写并不重要。这些设置放在一起,就构成了创建连接的基本信息。

尽管连接串是基于RDBMS(关系数据库管理系统)和使用的提供者的,其中只有一些信息是经常用到的:

数据库所在的服务器:本书的示例中,数据库服务器与ASP.NET应用基本上都处于同一台电脑上,环回别名localhost就代替了计算机名。

希望使用的数据库:本书的大多数示例使用Northwind数据库,它是大多数SQL Server默认安装的数据库。

数据库怎样进行授权:OracleSQL Server提供者使你能够选择信任机制或者作为当前用户进行登录。后者是最好的,因为这不需要你在代码中或者配置文件中放置密码信息。

举个例来说:下面是一个连接到Northwind数据库的连接字符串,数据库服务器位于本机,使用整合安全(integrated security,也就是说使用登录windows的用户访问数据库):

string connectionString = "Data Source=localhost;Initial Catalog=Northwind;" +"Integrated Security=SSPI";

如果不支持整合安全,连接必须指明一个有效的用户和密码组合。对于新安装的SQL Server数据库,sa(系统管理员)帐户通常都存在,下面的连接串使用了这个帐户:

String connectionString = “Data Source = localhost; Initial Catalog = Northwind;” + “user id = sa; password = opensesame”;

如果使用的是OLE DB提供者,连接串是相似的,只是需要额外的提供者设置来标识是OLE DB驱动器。例如,你可以使用下面的连接串,通过MSDAORA OLE DB提供者来连接到Oracle数据库。

String connectionString = “Data Source =- localhost; Initial Catalog = Sales;” + “user id = sa; password =; Provider = MSDAORA”;

连接到Access数据库文件的示例也在这里列出:

String connectionString = “ Provider = Microsoft.Jet.OLEDB.4.0;” +@”Data Source = c:/DataSources/Northwind.mdb”;

提示:如果使用的不是SQL Server,你需要查询相应的数据提供者文档,以确定支持的连接串值。例如,大多数数据库支持Connect Timeout设置,它在抛出异常前会有相应数量的时间来等待连接(SQL Server的默认值是15秒)。

你当你创建Connection对象时,可以将连接串作为构造函数的参数进行传递。同时,你可以在打开连接前,手工设置ConnectionString属性。

没有理由硬编码连接串。如第5章中讨论的那样,Web.config文件中的<connectionStrings>节很便于放置连接串。示例如下:

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

<connectionStrings>

<add name="Northwind" connectionString=

"Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI"/>

</connectionStrings>

...

</configuration>

你可以通过名字来获取连接串,这需要使用WebConfigurationManager.ConnectionStrings集,见下例:

String connectionString = WebConfigurationManager.ConnectionStrings[“Northwind”].ConnectionString;

接下来的例子都假设你已经将连接串添加到Web.config文件中了。

 

测试连接

一旦你选择了连接串,管理连接就非常容易了----你只需要使用Open() Close()方法就可以了。你可以Page.Load事件句柄中编写如下代码来测试连接,并且将它的状态写入到标签(图7-2所示):

// Create the Connection object.

string connectionString =

WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

SqlConnection con = new SqlConnection(connectionString);

try

{

// Try to open the connection.

con.Open();

lblInfo.Text = "<b>Server Version:</b> " + con.ServerVersion;

lblInfo.Text += "<br /><b>Connection Is:</b> " + con.State.ToString();

}

catch (Exception err)

{

// Handle an error by displaying the information.

lblInfo.Text = "Error reading the database. ";

lblInfo.Text += err.Message;

}

finally

{

// Either way, make sure the connection is properly closed.

// Even if the connection wasn't opened successfully,

// calling Close() won't cause an error.

con.Close();

lblInfo.Text += "<br /><b>Now Connection Is:</b> ";

lblInfo.Text += con.State.ToString();

}

7-2显示了运行结果

7-2 测试连接

 

连接限制了服务器资源。这句话的意思是要求你尽可能晚地打开连接,并且尽可能快地关闭连接。在前面的代码中,异常处理器用来保证发生没有处理的错误时,连接会在最后的代码块里关闭。如果不设计对异常的处理,直到垃圾收集器处理SqlConnection对象时,连接将保持打开状态。

另一个方法是在一个using块中对数据访问代码进行封装。Using语句声明你正在使用可以在短期内随意使用对象。只要using块结束,CLR就通过调用Dispose()方法,立即释放相应的对象。特别有意思的是,调用连接对象的Dispose()方法与调用Close()是一样的。这样你就可以将以前的代码写得更为精练,如下例所示:

string connectionString =

WebConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

SqlConnection con = new SqlConnection(connectionString);

using (con)

{

con.Open();

lblInfo.Text = "<b>Server Version:</b> " + con.ServerVersion;

lblInfo.Text += "<br /><b>Connection Is:</b> " + con.State.ToString();

}

lblInfo.Text += "<br /><b>Now Connection Is:</b> ";

lblInfo.Text += con.State.ToString();

最美妙的地方就是你无需再写finally块了,因为using声明释放了正在使用的对象,即便你退出的块是未处理异常的结果也是一样的。

 

连接池(Connection Pooling

获取连接会消耗一些时间,在Web应用中,当新的请求到达时,连接会被不断地打开和关闭,以高效地处理请求。在这种环境里,要求建立连接时负载很小变得很重要,并且成了系统扩展性的瓶颈。

一个解决办法就是连接池(Connection Pooling)。连接池就是在使用相同的数据源时,使会话共享的数据库连接保持持久的设置。这样可以避免总在创建和销毁连接。在ADO.NET中,连接池对于程序员是完全透明的,数据访问代码根本不需要修改。当客户通过调用Open()请求连接时,它直接从可获得的池中获得服务,而不是重新创建。当客户通过调Close()Dispose()释放连接时,也不需要丢弃连接,而是返回到池中,为下一个请求服务。

ADO.NET本身没有包含连接池机制。但是,多数ADO.NET提供者实现了连接池的某些形式。SQL ServerOracel 实现了它们自己的高效的连接池算法。这些算法在可管理代码中完全实现----这与某些流行的错误观念形成鲜明对比---不使用COM+企业服务。对于在SQL Server Orace中需要重用的连接来说,连接串能够精确匹配。如果稍有不同,在新的池中会创建新的连接。

提示:SQL ServerOracle池使用纯文本算法。意思就是连接串中的任何丁点的改变都会阻碍连接池,即便是简单地更改参数的顺序或者是在最后面添加一个额外的空格也不能使用连接池。它强制你在Web页中不进行硬编码连接串。相反,你应该在一个地方存放连接串(最好是在web.config)文件的<connectionStrings>节中存放)。

使用SQL ServerOracle提供者,连接池是可用的并且自动使用。然而,你也可以使用连接串参数来配置池的大小。

7-2 连接池设置

设置

描述

Max Pool Size

池中允许的最大连接数量(默认100),如果达到最大值,新的打开连接请求会放入队列,直到连接可用。(如果连接可用前,Connection.Timeout的值超时,会产生一个错误。)

Min Pool Size

池中保留的最少连接数(默认0)。当第一个连接被打开时,会创建相应数量的连接,这会导致第一个请求有一些延迟。

Pooling

设置为true时,连接会从池中提取,或者,在必要时,创建并添加到池中。

Connection Lifetime

指定几秒的时间间隔,如果连接返回到池中时超过了创建时设置的生存时间,它就会被销毁。默认值是0,也就是说禁止了这个行为。当你想立即反复使用大量的连接时,这个功能就会非常有用。

 

下面是设置了minimum pool size的连接串的示例:

string connectionString = "Data Source=localhost;Initial Catalog=Northwind;" +

"Integrated Security=SSPI;Min Pool Size=10";

SqlConnection con = new SqlConnection(connectionString);

// Get the connection from the pool (if it exists)

// or create the pool with 10 connections (if it doesn't).

con.Open();

// Return the connection to the pool.

con.Close();

有些提供者包含了清空连接池的方法。例如,使用SqlConnection,你可以调用静态的ClearPool()ClearAllPools()方法。当调用ClearPool()时,你提供一个SqlConnection,所有匹配的连接都将被移除。

ClearAllPools()在当前的应用域内,清空所有的连接池。(从技术上讲,这个方法并不关闭连接,只是将其标记为无效,这样它们就会超时,当规则的连接过会儿清除时,关闭它们)。这个功能很少使用。唯一的使用场合是,如果你知道池被无效连接充满了(如重启SQL Server时可能会造成这种情况),为了避免出错,才会用到。

提示:Sql ServerOracle连接池通常作为应用域内的全局资源的一部分被维护。因此,如果应用域重启,那么,所有的连接都将丢失(例如,由于更新或者达到了某个阀值)。与此类似,连接池不能够在同一Web服务器上互不相关的Web应用之间,或者在Web应用与其它的.NET应用之间重用连接池。

 

连接统计(Connection Statistics

如果使用SQL Server提供者,你可以使用SqlConnection.RetrieveStatistics()方法(.NET2.0以前没有这个方法)获得一些有趣的统计。RetrieveStatistics返回一个哈希表和不同的底层细节,来帮助你分析命令的性能和执行的任务的数量。连接统计在部署了的应用中并不会经常用到,但在测试和成型期间分析性能时很有用。例如,它们提供了一个工具,你可以使用它来确定不同的数据访问策略执行有何不同(其它工具包括SQL Server管理工具,如SQL ProfilerQuery Analyzer)。

默认的情况下,连接统计被禁用以提高性能。为了使用连接统计,你需要将SqlConnection.StatisticsEnabled属性设置为true。这样就告诉了SqlConnection类收集它执行的每个动作的信息。在任何断点之后,你都可以调用RetrieveStatistics()方法来检查这个信息,或者使用ResetStatistics()来清空它,然后重新开始捕捉。

下面的示例显示了开启统计功能后,从连接上接收的字节数:

Hashtable statistics = con.RetrieveStatistics();

lblBytes.Text = "Retrieved bytes: " + statistics["BytesRetrieved"].ToString();

统计在一个松散类型的名字/值集中提供。这意味着在获取统计之前必须知道它的名字。在MSDN中可以找到帮助列表,在这儿仅列出少数最有用的内容:

ServerRoundtrips:显示连接导致多少次到数据库的请求。典型地,这个值对应执行的命令的数量,诸如批处理命令之类的策略会对其造成影响。

ConnectionTime:显示连接被打开的累积数量。

BytesReceived:显示从数据库服务器获得的字节总数(执行的所有命令的累积结果)。

SumResultSets:显示执行的请求的次数。

SelectRows:记录执行每次请求获得的行的总数。

 

CommandDataReader

Command类允许你执行任何类型的SQL语句。尽管可以使用Command类执行数据定义(data-definition)任务(如创建和修改数据库、表和索引),你可能更愿意执行数据控制(data-manipulation)任务(如获取和更新表中的记录)

提供者明确的Command类执行标准的功能,就象Connection类一样。在这种情况下,IDbCommand接口定义了Command方法的核心集,用于在打开的连接上执行命令。

 

Command基础

在使用Command之前,你需要选择Command类型,设置command文本,并且将command绑定到connection,你可以通过设置对应的属性(CommandType, CommandText, Connection)来完成这项工作,或者将需要的信息作为构造器的参数进行传递。

Command文本可以是SQL语句,存储过程,或者表名。它取决于使用的Command类型。有三种command类型,已在表7-3中列出:

描述

CommandType.Text

Command将直接执行SQL语句,SQL语在CommandText属性中提供,这是默认值。

CommandType.StoreProcedure

Command将执行数据源中的存储过程,CommadnText属性提供了存储过程的名字。

CommandType.TableDirect

Command将查询表中的所有记录。CommandText是需要获取记录的表的名字。(这个选项是为了前向兼容,如OLE DB驱动。SQL SERVER数据提供者对此不支持,它也不能象明确目标的查询那样执行良好。)

7-3 CommandType枚举值

 

下面的示例就是创建一个Command对象来表示查询:

SqlCommand cmd = new SqlCommand();

cmd.Connection = con;

cmd.CommandType = CommandType.Text;

cmd.CommandText = “SELECT * FROM Emplyees”;

使用Command构造器会是效率更高的办法。注意,你不需要指定CommandType,因为CommandType.Text是默认的。

SqlCommand cmd = new SqlCommand(“SELECT * FROM Employees”, con);

除此之外,使用存储过程也是可以的,代码示例如下:

SqlCommand cmd = new SqlCommand(“GetEmployees”, con);

cmd.CommandType = CommandType.StoreProcedure;

这几个例子仅仅简单地定义了Command对象,它们并没有真正执行。Command对象提供了三种方法可用于执行Command,这取决于你是想要获得所有的结果集、单个值,或者仅仅是执行非查询请求(nonquery command)。表7-4列出了这几种方法:

方法

描述

ExecuteNonQuery()

执行non-SELECT命令,诸如insertdelete, updateSQL命令。返回值表示命令所影响的行数。

ExecuteScalar()

执行SELECT查询,并且返回从command命令产生的行集里的第一行的第一个字段。当在SELECT命令中执行使用COUNT()或者SUM()函数计算单个值的总计时,这个方法很有用。

ExecuteReader()

执行SELECT查询,并且返回DataReader对象,它包装了一个只读的、前向的游标。

 

DataReader

DataReader类可以读取通过SELECT命令返回的数据,一次一条记录,以只读、前向流的形式。有时这叫做火带游标(firehose cursor)。使用DataReader是获取数据的最简单的方法,但是它缺乏索引和未连接的DataSet的相关的能力,DataSet将在第8章介绍。尽管如此,DataReader提供了最快的无废话(no-nonsense)数据访问.

7-5列出了DataReader的核心方法。

 

方法

描述

Read()

在流中推进行游标到下一行。这个方法在读取第一行的数据前就要调用。(当DataReader第一次创建时,行游标被放置在第一行前)。如果还有别的行可读取,Read()方法返回true,如果游标位于最后一行,则返回false

GetValue()

在当前选择的行中,通过指定的列名或者索引,返回存储在字段中的值。返回值的类型与存储在数据源中的当地值最为匹配。如果通过索引访问字段,并且不小心传递了无效的索引,指向不存在的字段,就会抛出一个IndexOutOfRangeException异常。也可以通过名字来访问相同的值,只是这样效率会略低一点,因为DataReader要使用特定的名字来查找相应的行。

GetValues()

<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 26.75pt; TEXT-ALIGN: left; mso-char-inde

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值