单元5 使用ADO.NET访问数据库 使用ASP.NET开发Web应用程序时,为了使客户端能够访问服务器中的数据库,经常需要用到对数据库的各种操作,而这其中,ADO.NET技术是一种最常用的数据库操作技术。ASP.NET技术是一组向.NET开发人员公开数据访问服务的类,它为创建分布式数据共享应用程序提供了一组丰富的组件。本单元将对ADO.NET数据访问技术进行详细讲解。 本单元主要学习目标如下。 ◆理解ADO.NET的相关概念及其结构。 ◆掌握数据库的两种访问模式及其区别。 ◆熟练掌握Connection对象的使用。 ◆熟练掌握Command对象的使用。 ◆掌握DataReader对象的使用。 ◆熟练掌握 DataAdapter对象的使用。 ◆掌握DataSet对象中常用的方法,并高效使用DataSet开发。 5.1ADO.NET概述 ADO.NET是.NET Framework 提供的数据访问服务的类库,ADO.NET 对 Microsoft SQL Server、Oracle和XML等数据源提供一致的访问,应用程序可以使用ADO.NET连接到这些数据源,并检索和更新所包含的数据。 5.1.1ADO.NET简介 ADO.NET的名称起源于ADO(ActiveX Data Objects),ADO用于在以往的Microsoft技术中进行数据的访问。所以微软公司希望通过使用 ADO.NET 向开发人员表明,这是在.NET编程环境和Windows环境中优先使用的数据访问接口。 ADO.NET提供了平台互用性和可伸缩的数据访问,增强了对非连接编程模式的支持,并支持RICH XML。由于传送的数据都是XML格式的,因此任何能够读取XML格式的应用程序都可以进行数据处理。事实上,接收数据的组件不一定非要是ADO.NET组件,它可以是基于一个Microsoft Visual Studio的解决方案,也可以是运行在其他平台上的任何应用程序。 传统的ADO和ADO.NET是两种不同的数据访问方式,无论是在内存中保存数据,还是打开和关闭数据库的操作模式都不尽相同。 5.1.2ADO.NET的结构 1. ADO.NET的模型 ADO.NET采用层次管理模型,各部分之间的逻辑关系如图51所示。 图51ADO.NET的模型 ASP.NET网站开发项目化教程(第2版)微课视频版 单 元 5使用ADO.NET访问数据库 ADO.NET模型的最顶层是Web应用程序,中间是ADO.NET数据层和数据提供程序,在这个层次中数据提供程序相当于ADO.NET的通用接口,各种不同的数据源要使用不同的数据提供程序。 2. ADO.NET的主要组件 ADO.NET用于数据访问的类库包含.NET Framework数据提供程序和DataSet(数据集)两个组件。.NET Framework数据提供程序和DataSet之间的关系如图52所示。 图52ADO.NET的主要组件 .NET Framework数据提供程序包括以下四个核心对象。 (1) Connection: 建立与数据源的连接。 (2) Command: 对数据源执行操作命令,用于修改、查询数据和运行存储过程等。 (3) DataReader: 从数据源获取返回的数据。 (4) DataAdapter: 用数据源数据填充DataSet,并更新数据。 DataSet是ADO.NET的断开式结构的核心组件。设计DataSet的目的是为了实现独立于任何数据源的数据访问,可以把它看成是内存中的数据库,是专门用来处理数据源中读出的数据的。 DataSet的优点就是离线式,一旦读到数据库中的数据后,就在内存中建立数据库的副本,在此之后的操作,直到执行更新命令为止,所有的操作都是在内存中完成的。不管底层的数据库是哪种类型,DataSet的行为都是一致的。 DataSet是数据表(DataTable)的集合,它可以包含任意多个数据表,而且每个DataSet中的数据表对应一个物理数据库中的数据表(Table)或者数据视图(View)。 5.1.3与数据有关的命名空间 在ADO.NET中,连接数据源的接口有以下四种: SQLClient、OracleClient、ODBC、OLEDB。其中,SQLClient是Microsoft SQL Server数据库专用连接接口,OracleClient是Oracle 数据库专用连接接口,ODBC和OLEDB可用于其他数据源的连接。在应用程序中使用任何一种连接接口时,必须在后台代码中引用相应的命名空间,类的名称也随之发生变化,如表51所示。 表51ADO.NET的数据库命名空间及其说明 命 名 空 间 说明 System.Data ADO.NET的核心,包含处理非连接的架构所涉及的类,如DataSet System.Data.SqlClient SQL Server的.NET数据提供程序 System.Data.OracleClient Oracle的.NET数据提供程序 System.Data.OleDb OLE DB的.NET数据提供程序 System.Data.Odbc ODBC的.NET数据提供程序 System.Xml 提供基于标准XML的类、结构等 System.Data.Common 由.NET数据提供程序继承或者实现的工具类和接口 5.1.4ADO.NET数据提供者 ADO.NET的一个核心成员——数据提供者(Data Provider)是一个类库,它可以被看成是数据库与应用程序的一个接口或中间件。由于现在使用的数据源种类很多,在编写应用程序时就要针对不同的数据源编写不同的接口代码,工作量很大且效率低下。数据提供者针对这一问题向应用程序提供了统一的编程界面,向数据源提供了多种数据源接口,即对数据源进行了屏蔽,可以使应用程序不必关心数据源的种类。 ADO.NET提供与数据源进行交互的公共方法,但是对于不同的数据源要采用一组不同的类库,这些类库被称为数据提供者。数据提供者的命名通常是以与之交互的协议和数据源的类型来命名的。表52所示列出了一些常见的数据提供程序及其支持的数据源类型。 表52常见的数据提供程序及其支持的数据源类型 数据提供程序 支持的数据源类型 ODBC Data Provider 提供ODBC接口的数据源,包括Access、Oracle、SQL Server、MySQL和Visual FoxPro等老式数据源 OLE DB Data Provider 提供OLE DB接口的数据源,如Access、Excel、Oracle和SQL Server Oracle Data Provider 用于Oracle数据库 SQL Data Provider 用于Microsoft SQL Server 7或更高版本、SQL Express或MSDE Borland Data Provider许多数据库的公共存取方式,如Interbase、SQL Server、IBM DB2和Oracle 具体使用哪种数据提供程序,要根据应用程序所使用的数据库来确定。 5.1.5ADO.NET对象模型 ADO.NET对象是指包含在.NET Framework数据提供程序和数据集DataSet中的对象,其中,DataSet对象是驻留在内存中的数据库,位于System.Data命名空间下。ADO.NET从数据库中抽取数据后数据就存放在DataSet中,故可以把DataSet看成一个数据容器。.NET Framework数据提供程序包括Connection、Command、DataReader、DataSet和DataAdapter五个对象。ADO.NET对象关系模型如图53所示。 图53ADO.NET对象关系模型 ADO.NET的五大对象可以形象地记为连接Connection、执行Command、读取DataReader、填充DataSet、分配DataAdapter。这正是ADO.NET对数据库操作的一般步骤。下面将详细介绍这些对象。 5.2Connection数据连接对象 5.2.1Connection对象概述 当应用程序要访问数据时,怎样才能够找到数据库呢?这就需要使用Connection对象。在ADO.NE对象模型中,Connection对象用于连接到数据库和管理数据库的事务。不同的数据源(.NET 数据提供程序)需要使用不同的类来建立连接。例如,要连接到SQL Server,需要选择SqlConnection连接类。根据不同的数据源提供了表53所示的四种数据库连接方式。 表53.NET数据提供程序及对应的连接类 数据访问提供程序 名 称 空 间 对应的连接类名称 SQL Server数据提供程序 System.Data.SqlClient SqlConnection OLEDB数据提供程序 System.Data.OleDb OledbConnection ODBC数据提供程序 System.Data.Odbc OdbcConnection Oracle数据提供程序 System.Data.OracleClient OracleConnection 5.2.2Connection对象的常用属性和方法 ADO.NET使用 SqlConnection 对象与SQL Server 进行连接,下面以SqlConnection为例介绍Connection对象的使用。SqlConnection对象提供了一些属性和方法,允许程序员与数据源建立连接或断开连接。SqlConnection对象的常用属性和方法如表54所示。 表54SqlConnection对象的常用属性和方法 属性和方法 说明 ConnectionString属性 获取和设置数据库的连接字符串 ConnectionTimeOut属性 获取SqlConnection对象的超时时间,单位为秒,0表示不限时。如果在这段时间之内无法连接数据源,则产生异常 Database属性 获取当前数据库名称 DataSource属性 获取数据源的完整路径和文件名,如果是SQL Server数据库,则获取所连接的SQL Server服务器名称 State属性 获取数据库的连接状态,它的值为ConnectionState枚举值 Open方法 打开与数据库的连接 Close方法 关闭与数据库的连接 ChangeDatabase方法 在打开连接的状态下,更改当前数据库 CreateCommand方法 创建并返回与SqlConnection对象有关的SqlCommand对象 Dispose方法 调用Close方法关闭与数据库的连接,并释放所占用的系统资源 注意: 除了ConnectionString属性之外,其他属性都是只读属性,只能通过连接字符串的标记配置数据库连接。 在ADO.NET中,如果使用.NET Framework数据提供程序操作数据库,必须显示关闭与数据库的连接,也就是说在操作完数据库后,必须调用Connection对象的Close方法关闭连接。 5.2.3使用SqlConnection对象连接数据库 建立应用程序与数据库连接需要以下三个步骤。 1. 定义数据库连接字符串 定义连接字符串的常用方式有以下两种。 1) 使用 Windows身份验证 该方式又称信任连接,这种连接方式有助于在连接到 SQL Server时提供安全保护,因为它不会在连接字符串中公开用户ID和密码,是安全级别要求较高时推荐的数据库连接方法。其连接字符串的语法格式如下: string ConnStr="Server=服务器名或 IP;Database=数据库名;Integrated Security=true"; 2) 使用 SQL Server身份验证 该方式又称非信任连接,这种连接方式把未登录的用户 ID和密码写在连接字符串中,因此在安全级别要求较高的场合不要使用。其连接字符串的语法格式如下: string ConnStr="Server=服务器名;Database=数据库名;uid=用户名;pwd=密码"; 或 string ConnStr="Data Source=服务器名;Initial Catalog=数据库名; User ID=用户名;Pwd=密码"; 数据库连接字符串由多个分号隔开的多个参数组成,其常用参数及其说明如表55所示。 表55Sqlconnection对象的连接字符串参数及其说明 参数 说明 Data Source或Server 连接打开时使用的SQL Server数据库服务器名称,或者是Microsoft Access数据库的文件名,可以是"local"".""localhost""127.0.0.1",也可以是具体数据库服务器名称 Initial Catalog或Database 数据库的名称 Integrated Security 此参数决定连接是否是安全连接。可能的值有true、false和SSPI(SSPI是true的同义词) User ID或uid SQL Server账户的登录账号 Password或pwd SQL Server登录密码 例如,“新知书店”应用程序与本机的BookShopPlus数据库连接的字符串可以写成: String ConnStr="Server=.; Database=BookShopPlus; uid=sa; pwd=123456"; 说明: 如果数据库的密码为空,可以省略pwd这一项。 2. 创建Connection对象 使用定义好的连接字符串创建Connection对象,代码如下所示: SqlConnection sqlconn = new SqlConnection(connStr); 3. 打开与数据库的连接 调用Connection对象的Open方法打开与数据库的连接,代码如下: sqlconn.Open(); 在上面的这三个步骤中,第1、2步的先后顺序可以调换,即可以先创建一个Connection对象,再设置它的ConnectionString属性,例如: SqlConnection sqlconn = new SqlConnection(); String connStr="Server=.; Database=BookShopPlus; Uid=sa; pwd=123456"; sqlconn.ConnectionString=connStr; 注意: 打开数据库连接,执行命令后,要确保关闭数据库连接。 【示例51】使用SqlConnection对象连接数据库。 使用Connection对象建立与SQL Server数据库Student的连接,并显示当前数据库的连接状态。 (1) 在SQL Server 2014中附加数据库文件Student.mdf。 (2) 在WebSite05网站项目中创建文件夹Ch5_1,在文件夹Ch5_1下新建Web页面Default.aspx。在网页中添加一个Label标签控件和两个Button命令按钮,两个命令按钮的Text属性分别设置为“打开连接”和“关闭连接”。 (3) 在Default.aspx.cs文件中添加命名空间的引用,代码如下: using System.Data.SqlClient; 在Default.aspx.cs文件的所有事件之外定义数据库连接字符串和连接对象,代码如下: static string ConStr = " Server=.; Database=Student; Uid=sa; pwd=123456"; SqlConnection conn = new SqlConnection(ConStr); 在Default.aspx.cs文件中添加页面载入时执行的Page_Load事件过程代码,如下: protected void Page_Load(object sender, EventArgs e) { lblMsg.Text ="当前连接状态是: " + conn.State.ToString(); } 在Default.aspx.cs文件中分别添加单击“打开连接”和“关闭连接”按钮时执行的事件过程代码,如下: protected void btnConn_Click(object sender, EventArgs e) { conn.Open(); lblMsg.Text = "当前连接状态是: " + conn.State.ToString(); } protected void btnClose_Click(object sender, EventArgs e) { conn.Close(); lblMsg.Text = "当前连接状态是: " + conn.State.ToString(); } (4) 浏览该页面,页面载入时,显示的连接状态是Closed,打开连接时显示的连接状态是Open,结果如图54所示。 图54使用SqlConnection对象连接数据库 5.3Command命令执行对象 5.3.1Command对象概述 使用Connection对象与数据源建立连接后,可以使用Command对象对数据源执行查询、添加、删除和修改等各种操作,操作的实现方式可以是使用SQL语句,也可以是使用存储过程。同Connection对象一样,Command对象属于.NET Framework数据提供程序,不同的数据提供程序(数据源)有各自的Command对象,如表56所示。 表56.NET数据提供程序及对应的命令类 数据访问提供程序 名称空间 对应的命令类名称 SQL Server数据提供程序 System.Data.SqlClient SqlCommand OLE DB数据提供程序 System.Data.OleDb OledbCommand ODBC数据提供程序 System.Data.Odbc OdbcCommand Oracle数据提供程序 System.Data.OracleClient OracleCommand 5.3.2Command对象的常用属性和方法 SqlCommand对象的常用属性和方法如表57所示。 表57SqlCommand对象的常用属性和方法 属性和方法 说明 CommandText属性 获取或设置要对数据源执行的SQL命令、存储过程或数据表名称 CommandType属性 获取或设置命令类型,可取的值: CommandType.Text、CommandType.StoredProduce,分别对应SQL命令、存储过程,默认为Text Connection属性 获取或设置SqlCommand对象所使用的数据连接属性 Parameters属性 SQL命令参数集合 Cancel方法 取消SqlCommand对象的执行 CreateParameter方法 创建Parameter对象 ExecuteNonQuery方法 执行CommandText属性指定的内容,返回数据表被影响的行数。该方法只能执行Insert、Update和Delete命令 ExecuteReader方法 执行CommandText属性指定的内容,返回DataReader对象。该方法用于执行返回多条记录的Select命令 ExecuteScalar方法 执行CommandText属性指定的内容,以object类型返回结果表第一行第一列的值。该方法一般用来执行查询单值的Select命令 5.3.3创建Command对象 Command对象的构造函数的参数有两个,一个是需要执行的SQL语句,另一个是数据库连接对象。这里以它们为参数,调用 SqlCommand类的构造方法创建Command对象,语法格式如下: SqlCommand命令对象名 newSqlCommand(SOL语句,连接对象) 用户也可以首先使用构造函数创建一个不含参数的 Command 对象,再设置 Command对象的Connection属性和CommandText属性,其语法格式如下: SqlCommand命令对象名=new SqlCommand(); 命令对象名.Connection=连接对象; 命令对象名.CommandText=SOL语句; 5.3.4使用Command对象操作数据 使用Command对象操作数据,必须有一个Connection对象,使用Command对象进行数据操作的步骤如下。 (1) 创建数据库连接: 按照前面讲过的步骤创建一个Connection对象。 (2) 定义执行的SQL语句: 将对数据库执行的SQL语句赋给一个字符串。 (3) 创建Command对象: 使用已有的Connection对象和SQL语句字符串创建一个Command对象。 (4) 执行SQL语句: 使用Command对象的某个方法执行命令。 1. 使用Command对象增加数据库的数据 使用Command对象向数据库增加数据的一般步骤如下: 首先建立数据库连接; 然后创建Command对象,并设置它的Connection和CommandText属性; 最后,使用Command对象的ExecuteNoquery方法执行数据库增加命令,ExecuteNoquery方法表示要执行的是没有返回数据的命令。 【示例52】使用Command对象向数据库中添加新数据。 (1) 右击网站项目WebSite05新建文件夹Images,用于存放上传的学生照片。 (2) 在网站项目WebSite05中新建文件夹Ch5_2,并添加Web页面Default.aspx。在Default.aspx中添加相应Web控件,使其设计外观如图55所示,页面主体部分代码如下: <form id="form1" runat="server"> <div> <table style="width: 320px; height: 240px"> <tr> <td style="width: 100px; text-align: right"> 学号: </td> <td style="width: 220px"> <asp:TextBox ID="txtStuNo" runat="server"></asp:TextBox> </td> </tr> <tr> <td style="width: 100px; text-align: right">姓名: </td> <td style="width: 220px"> <asp:TextBox ID="txtName" runat="server"></asp:TextBox> </td> </tr> <tr> <td style="width: 100px; text-align: right">性别: </td> <td style="width: 220px"> <asp:DropDownList ID="DdSex" runat="server"> <asp:ListItem Selected="True">男</asp:ListItem> <asp:ListItem>女</asp:ListItem> 图55新增学生信息页面设计及运行效果 </asp:DropDownList> </td> </tr> <tr> <td style="width: 100px; text-align: right">出生日期: </td> <td style="width: 220px"> <asp:TextBox ID="txtBirth" runat="server"></asp:TextBox> </td> </tr> <tr> <td style="width: 100px; text-align: right">照片: </td> <td style="width: 220px"><asp:FileUpload ID="FileUpload1" runat="server" /></td> </tr> <tr> <td colspan="2" style="text-align: center"> <asp:Button ID="btnAdd" runat="server" Text="提交" OnClick="btnAdd_Click" /> </td> </tr> </table> </div> </form> (3) 在Default.aspx.cs文件的所有事件之外定义数据库连接字符串和连接对象,代码如下: static string ConStr = " Server=.; Database=Student; Uid=sa; pwd=123456"; SqlConnection conn = new SqlConnection(ConStr); (4) 编写Default.aspx页面中“添加”按钮的Click事件过程代码,如下: protected void btnAdd_Click(object sender, EventArgs e) { SqlCommand cmd = new SqlCommand(); //建立Command对象 cmd.Connection = conn; //把SQL语句赋给Command对象 cmd.CommandText = "insert into StuInfo(StuNo,Name,Sex,Birth,Photo)values (@StuNo,@Name,@Sex,@Birth,@Photo)"; //在执行之前告诉Command对象@StuNo、@Name、@Sex、@Birth、@Photo将来用谁来代替,即给 //参数赋值 SqlParameter[] paras = new SqlParameter[] { new SqlParameter("@StuNo", txtStuNo.Text), new SqlParameter("@Name", txtName.Text), new SqlParameter("@Sex", DdSex.Text), new SqlParameter("@Birth", txtBirth.Text), new SqlParameter("@Photo", txtStuNo.Text+".jpg") }; cmd.Parameters.AddRange(paras); try { conn.Open(); //打开连接 cmd.ExecuteNonQuery(); //执行SQL命令 if (FileUpload1.HasFile == true) //把学生的照片上传到网站的"images"文件夹中, //以学号为名字进行保存 { string fileName = this.txtStuNo.Text + ".jpg"; FileUpload1.SaveAs(Server.MapPath(("images/") + fileName)); } Response.Write("成功追加记录"); } catch (Exception ex) { Response.Write("错误原因: " + ex.Message); } finally { cmd = null; conn.Close(); conn = null; } } (5) 程序运行效果如图55所示。 2. 使用Command对象删除数据库的数据 使用Command对象删除数据的一般步骤如下: 首先建立数据库连接; 然后创建Command对象,并设置它的Connection和CommandText属性,即使用Command对象的Parameters属性来设置输入参数; 最后,使用Command对象的ExecuteNoquery方法执行数据删除命令。 【示例53】使用Command对象删除数据。 (1) 在网站项目WebSite05中新建文件夹Ch5_3,并添加Web页面CommDeleteDemo.aspx。在CommDeleteDemo.aspx中添加一个TextBox控件和一个Button控件,其中Button控件作为“删除”按钮,页面主体部分代码如下: <form id="form1" runat="server"> <div> 输入要删除学生的学号: <br /> <asp:TextBox ID="txtStuNo" runat="server"></asp:TextBox> <asp:Button ID="btnDel" runat="server" Text="删除" OnClick="btnDel_Click" /> </div> </form> (2) 编写CommDeleteDemo.aspx页面中“删除”按钮的Click事件过程代码,如下: protected void btnDel_Click(object sender, EventArgs e) { int intDeleteCount; string ConStr = "Server=.; Database=Student; Uid=sa; pwd=123456"; SqlConnection sqlconn = new SqlConnection(ConStr); //建立Command对象 SqlCommand cmd = new SqlCommand(); //给Command对象的Connection和CommandText属性赋值 cmd.Connection = sqlconn; cmd.CommandText = "delete from StuInfo where StuNo=@no"; //在执行之前告诉Command对象@no将来用谁来代替,注意与【示例5-2】的区别 SqlParameter p1 = new SqlParameter("@No", txtStuNo.Text); cmd.Parameters.Add(p1); try { sqlconn.Open(); intDeleteCount = cmd.ExecuteNonQuery(); if (intDeleteCount > 0) Response.Write("删除成功!"); else Response.Write("该记录不存在!"); } catch (Exception ex) { Response.Write("删除失败,错误原因: " + ex.Message); } finally { cmd = null; sqlconn.Close(); sqlconn = null; } } (3) 程序运行效果如图56所示。 图56页面CommDeleteDemo.aspx运行效果 3. 使用Command对象修改数据库的数据 使用Command对象修改数据库的数据和向数据库中添加数据的操作类似,在此不再举例,请读者自行完成。 任务51实现“新知书店”用户注册功能 【任务描述】 在任务44的基础上,新建“新知书店”用户信息注册Web页面Register.aspx,实现用户注册功能,注册成功后,弹出对话框,单击“确定”按钮时跳转到“新知书店”首页Default.aspx。注册页面运行效果如图57所示。 图57“新知书店”注册页面运行效果 【任务实施】 (1) 在文件夹rw51下创建网站项目Web,解决方案名称为BookShop,将任务44的站点目录下的文件及文件夹复制至新创建的网站项目Web下。 (2) 右击网站项目Web,添加名为Register.aspx的用户注册Web页。在Register.aspx页面中引入外部样式文件,添加必要的HTML代码,实现Web页面的布局结构。在Register.aspx页中添加相应Web控件,使其设计外观如图57所示。 (3) 在Register.aspx.cs文件中,编写方法IsExists,用于判断用户数据表“Users”中是否存在相同的注册信息,代码如下: static bool IsExists(string txtLoginId, string txtEmail) { string strSqlConn = "Server=.; Database=BookShopPlus; Uid=sa; pwd=123456"; string strSql = "Select * From Users Where LoginId='" + txtLoginId + "' Or Mail='" + txtEmail + "'"; SqlConnection sqlConn = new SqlConnection(); //创建连接对象 sqlConn.ConnectionString = strSqlConn; //给连接字符串赋值 sqlConn.Open(); //打开数据库连接 SqlCommand sqlComm = new SqlCommand(strSql, sqlConn); //创建命令对象 SqlDataReader sdr = sqlComm.ExecuteReader(); //读取数据表中的数据 //使用SqlDataReader对象的Read()方法判断是否存在记录,如果存在则返回True if (sdr.Read()) { sdr.Close(); return true; } else { sdr.Close(); return false; } } (4) “确定了,马上提交”按钮的Click事件过程代码实现新增用户注册信息,编写Register.aspx页面中“确定了,马上提交”按钮的btnSubmit_Click事件过程代码,如下: protected void btnSubmit_Click(object sender, EventArgs e) { string ConStr = "Server=.; Database=BookShopPlus; Uid=sa; pwd=123456"; SqlConnection conn = new SqlConnection(ConStr); SqlCommand cmd = new SqlCommand(); //建立Command对象 if (!CeckCode()) { Page.RegisterClientScriptBlock("alert", "<script>alert('验证码错误!')</script>"); return; } try { cmd.Connection = conn; //把SQL语句赋给Command对象 cmd.CommandText = "INSERT Users(LoginId, LoginPwd, Name, Address, Phone, Mail)VALUES (@LoginId, @LoginPwd, @Name, @Address, @Phone, @Mail)"; //在执行之前告诉Command对象@StuNo、@Name、@Sex、@Birth、@Photo将来用谁来代替,即给参数赋值 SqlParameter[] para = new SqlParameter[]{ new SqlParameter("@LoginId", txtLoginId.Text), new SqlParameter("@LoginPwd", txtLoginPwd.Text), new SqlParameter("@Name", txtName.Text), new SqlParameter("@Address", txtAddress.Text), new SqlParameter("@Phone", txtTele.Text), new SqlParameter("@Mail", txtEmail.Text) }; cmd.Parameters.AddRange(para); //调用IsExists()自定义方法判断数据表中是否存在相同的注册信息 if (!IsExists(txtLoginId.Text, txtEmail.Text)) { conn.Open(); //打开连接 cmd.ExecuteNonQuery(); //执行SQL命令 Page.RegisterClientScriptBlock("alert", "<script>alert('注册成功,请登录!');window.location='../Default.aspx'</script>"); } else { Page.RegisterClientScriptBlock("alert", "<script>alert('用户名已使用,请重新输入!')</script>"); } } catch (Exception ex) { Response.Write("错误原因: " + ex.Message); } finally { cmd = null; conn.Close(); conn = null; } } (5) 页面运行效果如图57所示。 5.4DataReader数据读取对象 5.4.1DataReader对象概述 当Command对象返回结果集时需要使用DataReader对象来检索数据。DataReader对象返回一个来自Command的只读的、只能向前的数据集。DataReader每次只能在内存中保留一行,所以开销非常小,提高了应用程序的性能。 由于 DataReader 只执行读操作,并且每次只在内存缓冲区里存储结果集中的一条数据,所以使用 DataReader对象的效率比较高,如果要查询大量数据,同时不需要随机访问和修改数据,DataReader是优先的选择。 DataReader属于.NET数据提供程序,每一种.NET数据提供程序都有与之对应的DataReader类,如表58所示。 表58.NET数据提供程序及对应的DataReader类 数据访问提供程序 名称空间 对应的DataReader类名称 SQL Server数据提供程序 System.Data.SqlClient SqlDataReader OLEDB数据提供程序 System.Data.OleDb OledbDataReader ODBC数据提供程序 System.Data.Odbc OdbcDataReader Oracle数据提供程序 System.Data.OracleClient OracleDataReader 5.4.2DataReader对象的常用属性和方法 SqlDataReader对象的常用属性和方法如表59所示。 表59SqlDataReader对象的常用属性和方法 属性和方法 说明 FieldCount属性 获取由DataReader得到的一行数据中的字段数 isClosed属性 获取SqlDataReader对象的状态,true表示关闭,false表示打开 HasRows属性 表示查询是否返回结果。如果有查询结果,返回true,否则返回false HasMoreRows属性 只读,表示是否还有记录未读取 Close方法 不带参数,无返回值,用来关闭DataReader对象 Read方法 让记录指针指向本结果集中的下一条记录,返回值是true或false NextResult方法 当返回多个结果集时,使用该方法让记录指针指向下一个结果集。当调用该方法获得下一个结果集后,依然要用Read方法来遍历访问该结果集 GetValue方法 根据传入的列的索引值,返回当前记录行里指定列的值。由于事先无法预知返回列的数据类型,所以该方法使用Object类型来接收返回数据 GetValues方法 该方法会把当前记录行里所有的数据保存到一个数组里。可以使用FieldCount属性来获知记录里字段的总数,据此定义接收返回值的数组长度 GetName方法 通过输入列索引,获得该列的名称。综合使用GetName和GetValue两个方法,可以获得数据表里列名和列的字段 IsDBNull方法 判断指定索引号的列的值是否为空,返回true或false 5.4.3创建DataReader对象 DataReader对象不能直接实例化,而必须调用Command对象的ExecuteReader方法才能创建有效的DataReader对象。通过调用Command对象的ExecuteReader方法得到的结果集是一个DataReader对象,语法格式如下,可以调用DataReader对象的Read方法读取一行记录。 SqlDataReader 数据读取器对象名 new命令对象名.ExecuteReader(); 5.4.4使用DataReader对象检索数据 使用DataReader对象读取数据,首先要使用其HasRows属性判断是否有数据可供读取,如果有数据,返回true,否则返回false; 然后再使用DataReader对象的Read方法来循环读取结果集中的数据; 最后通过访问DataReader对象的列索引来获取读取到的值,例如dr[“Id”]用来获取数据表中Id列的值。使用SqlDataReader对象检索数据的步骤如下。 (1) 创建SqlConnection对象,设置连接字符串。 (2) 创建SqlCommand对象,设置它的Connection和CommandText属性,分别表示数据库连接和需要执行的SQL命令。 (3) 打开与数据库的连接。 (4) 使用SqlCommand对象的ExecuteReader方法执行CommandText中的命令,并把返回的结果放在SqlDataReader对象中。假设已创建一个名为cmd的Command对象,下面的代码可以创建一个DataReader对象。 SqlDataReader dr=cmd.ExecuteReader(); (5) 通过调用SqlDataReade对象的Read方法循环读取查询结果集的记录。这个方法返回一个布尔值。如果能读到一行记录,返回true,否则返回false。代码如下: dr.Read(); (6) 读取当前行的某列的数据。可以像使用数组一样,用方括号来读取某列的值,如(type)dr[ ],方括号中可以是列的索引(从0开始),也可以是列名。读取到的列值必须要进行类型转换,如下: (string)dr[“name”]; (7) 关闭与数据库的连接。 【示例54】使用DataReader对象读取数据库中的数据。 (1) 在网站项目WebSite05中新建文件夹Ch5_4,在文件夹Ch5_4中添加一个名为DataReaderDemo.aspx的Web页。 (2) 在DataReaderDemo.aspx.cs文件的所有事件之外定义数据库连接字符串和连接对象,代码如下: static string ConStr = " Server=.; Database=Student; Uid=sa; pwd=123456"; SqlConnection conn = new SqlConnection(ConStr); (3) 编写DataReaderDemo.aspx页面的Page_Load事件过程代码,如下: protected void Page_Load(object sender, EventArgs e) { SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; cmd.CommandText = "select * from StuInfo"; SqlDataReader dr = null; //创建DataReader对象的引用 try { if (conn.State == ConnectionState.Closed) conn.Open(); //执行SQL命令,并获取查询结果 dr = cmd.ExecuteReader(); //依次读取查询结果的字段名称,并以表格的形式显示 Response.Write("<table border='1'><tr align='center'>"); for (int i = 0; i < dr.FieldCount; i++) { Response.Write("<td>" + dr.GetName(i) + "</td>"); } Response.Write("</tr>"); //如果DataRead对象成功获得数据,返回true,否则返回false while (dr.Read()) { //依次读取查询结果的字段值,并以表格的形式显示 Response.Write("<tr>"); for (int j = 0; j < dr.FieldCount; j++) { Response.Write("<td>" + dr.GetValue(j) + "</td>"); } Response.Write("</tr>"); } Response.Write("</table>"); } catch (Exception ex) { Response.Write("SqlDataReader读取出错,原因: " + ex.Message); } finally { if (dr.IsClosed == false) dr.Close();//关闭DataReader对象 if (conn.State == ConnectionState.Open) conn.Close(); } } (4) 页面运行效果如图58所示。 图58页面DataReaderDemo.aspx运行效果 使用SqlDataReader对象时,应注意以下几点。 (1) 读取数据时,SqlConnection对象必须处于打开状态。 (2) 必须通过调用SqlCommand对象的ExecuteReader方法产生SqlDataReader对象的实例。 (3) 只能按向下的顺序逐条读取记录,不能随机读取,且无法直接获知读取记录的总数。 (4) SqlDataReader对象管理的查询结果是只读的,不能修改。 任务52实现“新知书店”用户登录功能 【任务描述】 在任务44的基础上,创建名为UserLogin.aspx的用户登录Web页,该页面实现“新知书店”用户登录功能,其浏览效果如图59所示。如果用户名为空,则提示“请输入用户名!”,如果密码为空,则提示“请输入密码”。用户名和密码均输入,且与数据库查询验证通过后,则登录成功,自动弹出“登录成功”的提示信息对话框,并跳转到后台首页,在首页顶部显示登录的用户名,如图510所示,否则给出“登录失败”的提示信息。 图59“新知书店”用户登录页面 图510登录成功后的“新知书店”首页顶部 【任务实施】 (1) 在文件夹rw52下创建网站项目Web,解决方案名称为BookShop,将任务44的站点目录下的文件及文件夹复制至新创建的网站项目Web下。 (2) 右击网站项目Web,基于母版页common.master添加名为UserLogin.aspx的用户登录Web页。在UserLogin.aspx页面中引入外部样式文件,添加必要的HTML代码,实现Web页面的布局结构。在UserLogin.aspx页中添加相应Web控件,使其设计外观如图59所示,主体部分代码如下: <%@ Page Title="" Language="C#" MasterPageFile="~/common.master" AutoEventWireup="true" CodeFile="UserLogin.aspx.cs" Inherits="UserLogin" %> <asp:Content ID="Content1" ContentPlaceHolderID="cphHeader" runat="Server"> <link href="Css/member.css" rel="stylesheet" type="text/css" /> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="cphContent" runat="Server"> <script type="text/javascript"> function ValidateForm() { var txtLoginId = document.getElementById('<%= txtUserName.ClientID %>'); var txtLoginPwd = document.getElementById('<%= txtPassword.ClientID %>'); if (txtLoginId.value == "") { alert('请输入用户名!'); return false; } else if (txtLoginPwd.value == "") { alert("请输入密码!"); return false; } return true; } document.forms[0].onsubmit = function () { if (ValidateForm() == false) { return false; } else { document.forms[0].submit(); } } </script> <div id="action_area" class="member_form"> <h2 class="action_type"> <img src="Images/login_in.gif" alt="会员登录" /></h2> <p class="state"> 欢迎光临新知书店网站!<br /> 您可以使用新知书店的用户名,直接登录。</p> <p> <label> 用户名</label><asp:TextBox ID="txtUserName" runat="server" CssClass="opt_input"></asp:TextBox></p> <p> <label> 密    码</label><asp:TextBox ID="txtPassword" runat="server" TextMode="Password" CssClass="opt_input"></asp:TextBox></p> <p class="form_sub"> <input type="checkbox" name="" checked="checked" /> 在此计算机上保留我的密码</p> <p class="form_sub"> <asp:Button runat="server" ID="btnLogin" CssClass="opt_sub" Text="登录" TabIndex="1" OnClick="btnLogin_Click" /> <a href="Register.aspx">还没有注册??</a></p> </div> </asp:Content> (3) “登录”按钮的Click事件过程代码实现用户登录,编写UserLogin.aspx页面中“登录”按钮的btnLogin_Click事件过程代码,如下: protected void btnLogin_Click(object sender, EventArgs e) { //声明一个连接数据库字符串 string strSqlConn = "Server=.; Database=BookShopPlus; Uid=sa; pwd=123456"; string strSqlComm = "Select * From Users Where LoginId='" + txtUserName.Text.Trim() +"' And LoginPwd='" + txtPassword.Text.Trim() + "'" + "And UserRoleId=3"; SqlConnection sqlConn = new SqlConnection(strSqlConn); sqlConn.Open();//打开连接 //建立SqlCommand命令对象1 SqlCommand sqlComm = new SqlCommand(strSqlComm, sqlConn); //使用DataReader对象执行命令 SqlDataReader sdr = sqlComm.ExecuteReader(); //读取查询数据 if (sdr.Read()) { Response.Write("<script>alert('登录成功!')</script>"); Session["LoginUserName"] = txtUserName.Text.Trim(); Session["LoginPassword"] = txtPassword.Text.Trim(); Response.Redirect("Default.aspx?name=" + this.txtUserName.Text.Trim()); Session["LoginTime"] = DateTime.Now.ToString(); } else { Response.Write("<script>alert('登录失败!')</script>"); } sdr.Close(); sqlConn.Close(); } (4) 页面运行效果如图59和图510所示。 说明: 由于显示用户信息的首页顶部是在母版页中设计完成的,在UserLogin.aspx页面中登录后,用户登录信息被传递给网站首页Default.aspx,因此,要在Default.aspx页中添加<%@ MasterType VirtualPath ="common.master" %>标记,以便母版页获取传递给Default.aspx页的用户信息,具体参看4.3.4节【示例44】。 5.5DataSet对象和DataAdapter对象 5.5.1DataSet对象 1. DataSet对象概述 DataSet对象是ADO.NET 的核心组件之一。ADO.NET从数据库抽取数据后数据就存放在DataSet中,故可以把 DataSet看成一个数据容器,或称为“内存中的数据库”。 DataSet从数据源中获取数据后就断开了与数据源之间的连接。用户可以在DataSet中对记录进行插入、删除、修改、查询、统计等,在完成了各项操作后还可以把DataSet中的数据送回数据源。 每一个DataSet 都是一个或多个DataTable对象的集合,DataTable相当于数据库中的表。DataTable对象的常用属性主要有Columns属性、Rows属性和Default View属性。 (1) Columns属性: 用于获取DataTable对象中表的列集合。 (2) Rows属性: 用于获取DataTable对象中表的行集合。 (3) Default View属性: 用于获取表的自定义视图。 2. DataSet对象结构模型 DataSet数据集对象的结构和我们熟悉的SQL Server非常相似,如图511所示。在SQL Server数据库中,有很多数据表,每个数据表都有行和列。DataSet数据集中也包含多个表,这些表构成了一个数据表集合(DataTableCollection),其中每个数据表都是一个DataTable对象。在每个数据表中又有列和行,所有的列构成了数据列集合(DataColumnCollection),其中每个数据列是一个DataColumn对象; 所有的行构成了数据行集合(DataRowCollection),每一行是一个DataRow对象。此外,在DataSet中还可以定义表之间的链接、视图等。 图511DataSet数据集对象基本结构 注意: 各个数据表DataTable之间的关系通过DataRelation来表示,这些DataRelation构成的集合就是DataRelationColleciton对象。 3. DataSet对象工作原理 DataSet数据集对象工作原理如图512所示。 图512DataSet数据集对象工作原理 当应用程序需要获取一些数据时,先向数据库服务器发出请求,要求获得数据。服务器将数据发送到DataSet数据集,然后再将数据集传递给客户端。客户端应用程序修改数据集中的数据后,统一将修改过的数据集发送到服务器,服务器接收数据集修改数据库中的数据。 4. 创建DataSet(数据集)对象 创建DataSet的语法格式为: DataSet对象名 = new DataSet(); 或 DataSet对象名 = new DataSet("数据集名"); 例如,创建数据集对象dsStu,代码如下: DataSet dsStu = new DataSet(); 或 DataSet dsStu = new DataSet("Student"); 注意: 方法中的参数是数据集的名称字符串,可以有,也可以没有。如果没有写参数,创建的数据集名称就默认为NewDataSet。 DataSet对象的常用属性和方法如表510所示。 表510DataSet对象的常用属性和方法 属性和方法 说明 DataSetName属性 获取或设置DataSet对象的名称 Tables属性 获取包含在DataSet数据集中的数据表的集合 Clear方法 删除DataSet对象中所有表 Copy方法 复制DataSet的结构和数据,返回与本DataSet对象具有相同结构和数据的DataSet对象 5. 创建DataTable(数据表)对象 DataSet中的每个数据表都是一个DataTable对象。定义DataTable对象的语法格式为: DataTable对象名 = new DataTable(); 或 DataTable对象名 = new DataTable("数据表名"); 例如,创建数据表对象dtStuInfo,代码如下: DataTable dtStuInfo = new DataTable(); dtStuInfo.TableName="StuInfo"; 或 DataTable dtStuInfo = new DataTable("StuInfo"); 创建好的数据表对象可以添加到数据集对象中,例如把创建好的 dtStuInfo数据表对象添加到数据集对象dsStu中,代码如下: dsStu.Tables.Add(dtStuInfo); DataTable对象的常用属性和方法如表511所示。 表511DataTable对象的常用属性和方法 属性和方法 说明 Columns属性 获取数据表的所有字段 DataSet属性 获取DataTable对象所属的DataSet对象 DefaultView属性 获取与数据表相关的DataView对象 PrimaryKey属性 获取或设置数据表的主键 Rows属性 获取数据表的所有行 TableName属性 获取或设置数据表名 Clear()方法 清除表中所有的数据 NewRow()方法 创建一个与当前数据表有相同字段结构的数据行 6. 创建DataRow(数据行)对象 DataTable对象可以包含多个数据行,每行就是一个DataRow对象。定义DataRow对象的语法格式为: DataRow对象名 = DataTable对象.NewRow(); 注意: DataRow对象不能用New来创建,而需要用数据表对象的NewRow方法创建。 例如,为数据表对象dtStuInfo添加一个新的数据行,代码如下: DataRow dr = dtStuInfo.NewRow(); 访问一行中某个单元格内容的方法为: DataRow对象名["字段名"]或DataRow对象名[序号] DataRow对象的常用属性和方法如表512所示。 表512DataRow对象的常用属性和方法 属性和方法 说明 RowState属性 获取数据行的当前状态,属于DataRowState枚举型,分别为: Add、Delete、Detached、Modified、Unchanged BeginEdit方法 开始数据行的编辑 CancelEdit方法 取消数据行的编辑 Delete方法 删除数据行 EndEdit方法 结束数据行的编辑 7. 创建DataColumn(数据列)对象 DataTable对象中包含多个数据列,每列就是一个DataColumn对象。定义DataColumn对象的语法格式为: DataColumn对象名 = new DataColumn(); 或 DataColumn对象名 = new DataColumn("字段名"); 或 DataColumn对象名 = new DataColumn("字段名",数据类型); 例如,创建数据列对象stuNoColumn,代码如下: DataColumn stuNoColumn= new DataColumn(); stuNoColumn.ColumnName=" StuNo"; stuNoColumn.DataType =System.Type.GetType("System.String"); 或 DataColumn stuNoColumn= new DataColumn("StuNo", System.Type.GetType("System.String")); 创建好的数据列对象可以添加到数据表对象中,例如将创建的数据列对象 stuNoColumn添加到刚才创建的数据表对象dtStuInfo中,代码如下: dtStuInfo.Columns.Add(stuNoColumn); DataColumn对象的常用属性如表513所示。 表513DataColumn对象的常用属性 属性 说明 AllowDBNull 设置该字段可否为空值,默认为true Caption 获取或设置字段标题。如果为指定字段标题,则字段标题与字段名相同 ColumnName 获取或设置字段名 DataType 获取或设置字段的数据类型 DefaultValue 获取或设置新增数据行时,字段的默认值 说明: 通过DataColumn对象的DataType属性设置字段数据类型时,不可直接设置数据类型,而要按照以下语法格式: 对象名.DataType = System.Type.GetType("数据类型"); 5.5.2DataAdapter对象 1. DataAdapter对象概述 DataAdapter(即数据适配器)对象是一种用来充当DataSet对象与实际数据源之间桥梁的对象。DataSet 对象是一个非连接的对象,它与数据源无关。DataAdapter 正好负责填充它,并把它的数据提交给一个特定的数据源。DataAdapter与DataSet配合使用可以执行新增、查询、修改和删除等多种操作。 DataAdapter对象是一个双向通道,用来把数据从数据源中读到一个内存表中,以及把内存中的数据写回到一个数据源中。这两种情况下使用的数据源可能相同,也可能不相同。这两种操作分别称为填充(Fill)和更新(Update)。 DataAdapter属于.NET数据提供程序,每一种.NET数据提供程序都有与之对应的DataAdapter类,如表514所示。 表514.NET数据提供程序及对应的DataAdapter类 数据访问提供程序 名称空间 对应的DataAdapter类名称 SQL Server数据提供程序 System.Data.SqlClient SqlDataAdapter OLE DB数据提供程序 System.Data.OleDb OledbDataAdapter ODBC数据提供程序 System.Data.Odbc OdbcDataAdapter Oracle数据提供程序 System.Data.OracleClient OracleDataAdapter 2. DataAdapter对象的主要属性和方法 1) DataAdapter对象的主要属性 (1) SelectCommand属性: 获取或设置一个语句或存储过程,用于在数据库中选择记录。 (2) InsertCommand属性: 获取或设置一个语句或存储过程,用于在数据库中插入记录。 (3) UpdateCommand属性: 获取或设置一个语句或存储过程,用于更新数据库中的记录。 (4) DeleteCommand属性: 获取或设置一个语句或存储过程,用于从DataSet数据集中删除记录。 2) DataAdapter对象的主要方法 (1) Fill方法: 调用Fill方法会自动执行SelectCommand属性中提供的命令,获取结果集并填充数据集的DataTable对象。其本质是通过执行SelectCommand对象的Select语句查询数据库,返回DataReader对象,通过DataReader对象隐式地创建DataSet中的表,并填充DataSet中表行的数据。 (2) Update方法: 调用InsertCommand、UpdateCommand和DeleteCommand属性指定的SQL命令,将DataSet对象更新到相应的数据源。在Update方法中,逐行检查数据表每行的RowState属性值,根据不同的RowState属性,调用不同的Command命令更新数据库。 3. 创建DataAdapter对象 DataAdapter对象构造函数的参数有两个,一个是需要执行的SQL语句,另一个是数据库连接对象。这里以它们为参数,调用SqlDataAdapter 类的构造方法创建DataAdapter对象,其语法格式如: SqIDataAdapter数据适配器对象名=new SqlDataAdapter(SOL语句,连接对象); 用户也可以首先使用构造函数创建一个不含参数的DataAdapter对象,再设置DataAdapter对象的Connection属性和CommandText属性,其语法格式如下: SqlDataAdapter数据适配器对象名=new SqlDataAdapter(); 数据适配器对象名.Connection=连接对象; 数据适配器对象名.CommandText=SQL语句; 4. DataSet和DataAdapter对象应用 使用SqlDataAdapter和DataSet对象操作数据库的步骤如下。 (1) 创建数据库连接对象。 (2) 利用数据库连接对象和Select语句创建SqlDataAdapter对象。 (3) 根据操作要求配置SqlDataAdapter对象中不同的Command属性。例如增加数据库数据,需要配置InsertCommand属性; 修改数据库数据,需要配置UpdateCommand属性; 删除数据库数据,需要配置DeleteCommand属性。 (4) 使用SqlDataAdapter对象的Fill方法把Select语句的查询结果放在DataSet对象的一个数据表中或直接放在一个DataTable对象中。 (5) 对DataTable对象中的数据进行增加、删除、修改操作。 (6) 修改完成后,通过SqlDataAdapter对象的Update方法将DataTable对象中的修改更新到数据库。 说明: 第(3)步中根据操作要求配置SqlDataAdapter对象中不同的Command属性,如果自己给SqlDataAdapter对象的InsertCommand、UpdateCommand、DeleteCommand属性定义SQL更新语句,过程比较复杂。可以通过建立CommandBuilder对象以便自动生成DataAdapter的Command命令。 1) 查询数据库的数据 使用DataSet和DataAdapter对象查询数据库数据的一般步骤如下: 首先建立数据库连接; 然后利用数据连接和Select语句建立DataAdapter对象,并使用DataAdapter对象的Fill方法把查询结果放在DataSet对象的一个数据表中; 接下来,将该数据表复制到DataTable对象中; 最后,实施对DataTable对象中数据的查询。 【示例55】使用DataSet和DataAdapter对象查询数据库的数据。 (1) 在网站项目WebSite05中新建文件夹Ch5_5,在文件夹Ch5_5中添加一个名为DataAdapterSelectDemo.aspx的Web页。 (2) 编写DataAdapterSelectDemo.aspx页面的Page_Load事件过程代码,如下: protected void Page_Load(object sender, EventArgs e) { string ConStr = " Server=.; Database=Student; Uid=sa; pwd=123456"; SqlConnection sqlconn = new SqlConnection(ConStr); DataSet ds = new DataSet(); //建立DataSet对象 DataRow dr; //建立DataRow数据行对象 try { sqlconn.Open(); //打开连接 SqlDataAdapter sda = new SqlDataAdapter("select * from StuInfo", sqlconn); //建立DataAdapter对象 sda.Fill(ds, "StuTable"); //用Fill方法返回的数据,填充DataSet,数据表取名为 //"StuTable" DataTable dtable = ds.Tables["StuTable"]; //将数据表StuTable的数据复制到 //DataTable对象 DataRowCollection drc = dtable.Rows; //用DataRowCollection对象获取StuTable数 //据表的所有数据行 for (int i = 0; i < drc.Count; i++)//逐行遍历,取出各行的数据 { dr = drc[i]; Response.Write("学号: " + dr["StuNo"] + " 姓名: " + dr["Name"] + " 性别: " + dr["Sex"] + " 出生日期: " + dr["Birth"] + " 照片: " + dr["Photo"]); Response.Write("<br />"); } } catch (Exception ex) { Response.Write("数据读取出错!原因: " + ex.Message); } finally { sqlconn.Close(); sqlconn = null; } } (3) 程序运行效果如图513所示。 图513页面DataAdapterSelectDemo.aspx运行效果 在后续章节介绍完绑定控件GridView后,显示DataSet中的数据更加简单。 2) 新增数据库的数据 使用DataSet和DataAdapter对象增加数据库数据的一般步骤如下: 首先建立数据库连接; 然后利用数据连接和Select语句建立DataAdapter对象,并建立CommandBuilder对象以便自动生成DataAdapter的Command命令,否则,就要自己给InsertCommand、UpdateCommand、DeleteCommand属性定义SQL更新语句; 使用DataAdapter对象的Fill方法把Select查询语句结果放在DataSet对象的一个数据表中; 接下来,将该数据表复制到DataTable对象中; 最后,向DataTable对象增加数据记录,并通过DataAdapter对象的Update方法向数据库提交数据。 【示例56】使用DataSet和DataAdapter对象向数据库增加一条学生记录。 (1) 在网站项目WebSite05中新建文件夹Ch5_6,在文件夹Ch5_6中添加一个名为DataAdapterInsertDemo.aspx的Web页。 (2) 编写DataAdapterInsertDemo.aspx页面中“提交”按钮的Click事件过程代码,如下: protected void btnAdd_Click(object sender, EventArgs e) { string ConStr = " Server=.; Database=Student; Uid=sa; pwd=123456"; SqlConnection sqlconn = new SqlConnection(ConStr); DataSet ds = new DataSet(); //建立DataSet对象 try { sqlconn.Open(); //打开连接 //建立DataAdapter对象 SqlDataAdapter sda = new SqlDataAdapter("select * from StuInfo", sqlconn); //设置DataAdapter的InsertCommand命令 SqlCommand command = new SqlCommand("insert into StuInfo(StuNo,Name,Sex,Birth,Photo)values (@StuNo,@Name,@Sex,@Birth,@Photo)", sqlconn); // Add the parameters for the InsertCommand. command.Parameters.Add("@StuNo", SqlDbType.NChar, 5, "StuNo"); command.Parameters.Add("@Name", SqlDbType.NVarChar, 40, "Name"); command.Parameters.Add("@Sex", SqlDbType.NChar, 5, "Sex"); command.Parameters.Add("@Birth", SqlDbType.DateTime, 40, "Birth"); command.Parameters.Add("@Photo", SqlDbType.NChar, 5, "Photo"); sda.InsertCommand = command; //SqlCommandBuilder cb = new SqlCommandBuilder(sda); //建立 CommandBuilder 对象 //来自动生成 DataAdapter 的 //Command 命令 sda.Fill(ds, "stuTable"); //用Fill方法返回的数据,填充DataSet,数据表取名为 //"stuTable" DataTable dtable = ds.Tables["stuTable"]; //将数据表stuTable的数据复制到 //DataTable对象 if (FileUpload1.HasFile == true) //把学生的照片上传到网站的"images"文件夹中, //以学号为名字进行保存 { string fileName = this.txtStuNo.Text + ".jpg"; FileUpload1.SaveAs(Server.MapPath(("images/") + fileName)); } DataRow dr = ds.Tables["stuTable"].NewRow(); //增加新记录 //给该记录赋值 dr["StuNo"] = txtStuNo.Text.Trim(); dr["Name"] = txtName.Text.Trim(); dr["Sex"] = DdSex.SelectedValue; dr["Birth"] = Convert.ToDateTime(txtBirth.Text.Trim()); dr["Photo"] = txtStuNo.Text.Trim() + ".jpg"; dtable.Rows.Add(dr); sda.Update(ds, "stuTable"); //提交更新 Response.Write("增加成功<hr>"); } catch (Exception ex) { Response.Write("记录新增失败,原因: " + ex.Message); } finally { sqlconn.Close(); sqlconn = null; Response.Write("<h7>成功关闭SQL Server数据库的连接</h7><hr>"); } } (3) 程序运行效果如图514所示。 图514DataAdapterInsertDemo.aspx页面设计及运行效果 3) 修改数据库的数据 使用DataSet和DataAdapter对象修改数据库数据和向数据库中添加数据的操作类似,在此不再举例,请读者自行完成。 4) 删除数据库的数据 使用DataSet和DataAdapter对象删除数据库数据的一般步骤如下: 首先建立数据库连接; 然后利用数据连接和Select语句建立DataAdapter对象; 定义DeleteCommand属性,自定义Delete命令; 使用DataAdapter对象的Fill方法把Select语句的查询结果放在DataSet对象的数据表中; 接下来,将该数据表复制到DataTable对象中; 最后,删除DataTable对象中的数据,并通过DataAdpter对象的Update方法向数据库提交数据。 【示例57】使用DataSet和DataAdapter对象删除符合条件的记录。 (1) 在网站项目WebSite05中新建文件夹Ch5_7,在文件夹Ch5_7中添加一个名为DataAdpterDeleteDemo.aspx的Web页。 (2) 编写DataAdpterDeleteDemo.aspx页面中“删除”按钮的Click事件过程代码,如下: protected void btnDel_Click(object sender, EventArgs e) { string strCnn = " Server=.; Database=Student; Uid=sa; pwd=123456"; DataSet ds = new DataSet(); using (SqlConnection cnn = new SqlConnection(strCnn)) { SqlDataAdapter sda = new SqlDataAdapter("select * from StuInfo", cnn); //定义DeleteCommand属性,自定义Delete命令,其中@StuNo是参数 sda.DeleteCommand = new SqlCommand("delete from StuInfo where StuNo=@StuNo", cnn); //定义@StuNo参数对应于StuInfo表的StuNo列 sda.DeleteCommand.Parameters.Add("@StuNo", SqlDbType.VarChar, 8, "StuNo"); sda.Fill(ds, "StuTable"); //调用Fill方法,填充DataSet的数据表StuTable DataTable dtable = ds.Tables["StuTable"]; //将数据表StuTable的数据复制到 //DataTable对象 //设置dtStuInfo的主键,便于后面调用Find方法查询记录 dtable.PrimaryKey = new DataColumn[] { dtable.Columns["StuNo"] }; //根据txtStuNo文本框的输入查询相应的记录,以便修改 DataRow dr = dtable.Rows.Find(txtStuNo.Text.Trim()); if (dr != null) //如果存在相应记录,则删除并更新到数据库 { dr.Delete(); //删除行记录 sda.Update(dtable); //提交更新 Response.Write( "记录删除成功!"+ "<hr>"); } else { Response.Write("没有该记录!"+"<hr>"); } } } (3) 程序运行效果如图515所示。 图515DataAdpterDeleteDemo.aspx页面设计及运行效果 单 元 小 结 本单元主要介绍了如何使用 ADO.NET访问数据库。ADO.NET是一个访问数据源通用接口,它允许以编程方式从Web窗体访问数据源。ADO.NET允许使用Command和DataReader对象与数据库进行直接的交互,同时还以DataAdapter和DataSet对象的方式提供了一种高级、抽象的数据访问机制,实现断开式数据库操作。第一种方法需要的代码非常少,但可以完成大量工作; 而第二种方法可以减少服务器的负担,使服务器获得更好的性能。ADO.NET是一种强大的高性能数据库技术,在.NET体系中占据着举足轻重的位置,读者要熟练掌握。 单元练习题 一、 选择题 1. ()对象用于从数据库中获取仅向前的只读数据流,并且在内存一次只能存放一行数据。此对象具有较好的功能,可以简单地读取数据。 A. DataAdapterB. DataSetC. DataViewD. DataReader 2. Command对象执行查询语句时,调用()方法会返回结果集中的第一条记录的第一个字段的值。 A. ExecuteNonQueryB. ExecuteReader C. ExecuteScalarD. ExecuteXmlReader 3. 如果要从数据库中获取多行记录,应该使用Command对象的()方法。 A. ExecuteNonQueryB. ExecuteReaderC. ExecuteScalar 4. 如果要对数据库执行修改、插入和删除操作,应该使用Command对象的()方法。 A. ExecuteNonQueryB. ExecuteReaderC. ExecuteScalar 5. ()是开发人员要使用的第一个对象,被要求用于任何其他ADO.NET对象之前。 A. CommandBuilder对象B. 命令对象 C. 连接对象 D. DataAdapter对象 6. ()表示一组相关表,在应用程序中这些表作为一个单元被引用。使用此对象可以快速从每一个表中获取所需的数据,当服务器断开时检查并修改数据,然后在下一次操作中使用这些修改的数据更新服务器。 A. DataTable对象B. DataRow对象C. DataReader对象D. DataSet对象 7. 数据适配器DataAdapter填充数据集的方法是()。 A. FillB. GetChangesC. AcceptChangesD. Update 8. 如果Command对象执行的是存储过程,其属性CommandType应取()。 A. CommandType.TextB. CommandType.StoredProcedure C. CommandType.TableDirectD.没有限制 9. 如果希望将FlightNumber字段的值在包含信息字段的表的第一个<td>元素中显示,要在表格的<td>元素添加()代码以显示FlightNumber字段。 A. <td><%=FlightNumber%></td> B. <td><script runat="server">FlightNumber</script></td> C. <td><script>document.write("FlightNumber");</scripts></td> D. <td>=FlightNumber</td> 二、 问答题 1. 列举常见的数据提供者,并且简单介绍对应的命名空间及作用。 2. 分别说明SqlCommand对象的ExecuteReader、ExecuteNonQuery和ExecuteScalar方法的作用。 3. 简述DataSet与DataTable的区别与联系。 4. 简述SqlDataAdapter对象查询数据库数据的步骤。