ASP.NET数据库访问系列教程
本教程深入探讨了基于ASP.NET 2.0技术的数据库访问方法和模式。这些介绍非常简明,并且提供了一步步的指导和大量的截屏。
该系列教程包括:
- 概述篇
- 基础报表
- 主/明细报表
- 自定义格式报表
- 编辑,插入和删除数据
- 分页和排序、自定义按钮事件
- 使用DataList和Repeater控件显示数据
- 使用DataList和Repeater进行数据筛选
- 通过DataList编辑和删除数据
- 使用DataList和Repeater控件进行分页和排序
- 自定义DataList和Repeater控件的按钮事件
- 从ASP.NET页面直接访问数据库
- 扩展GridView控件
- 操作二进制文件
- 数据缓存
- 基于数据库的站点地图
- 批量数据处理
- 高级数据库访问操作
#1 概述篇-创建数据访问层(上)
该教程从头开始使用 Typed DataSet(强类型 DataSet)创建数据访问层 (DAL),以访问数据库中的信息。
Download the code for this tutorial | Download the tutorial in PDF format
简介
作为web 开发人员,我们的工作总是在和数据打交道。我们创建数据库来存储数据,编写代码来检索并修改数据,并创建Web页面来收集和汇总数据。这是探讨在ASP.NET 2.0 中实现这些常用类型的技巧的系列教程中的首篇教程。我们从创建一个 软件架构 开始,包括使用Typed DataSet 的数据访问层(DAL) 、实现自定义业务规则的业务逻辑层(BLL) 和共享同一页面布局的ASP.NET 页面组成的表示层。一旦奠定了这个基础,我们接下来会转向报表,说明如何显示、汇总、收集和验证来自Web 应用程序的数据。这些教程力求简明,使用大量屏幕截图逐步教您直观地了解整个流程。每个教程都提供C# 和Visual Basic 版本,并且可以下载所使用的全部代码。(这篇教程内容非常冗长,但接下来会分几大部分进行介绍,使人更容易理解和消化。)
针对这些教程,我们将使用放在 App_Data 目录下 Northwind 数据库的 Microsoft SQL Server 2005 Express Edition 版本。除数据库文件外,App_Data 文件夹也包含创建该数据库的 SQL 脚本,以满足您想使用不同数据库版本的需求。如果愿意,这些脚本也可以直接从 Microsoft 下载 。如果您使用的是 Northwind 数据库的不同 SQL Server 版本,需要更新该应用程序的Web.config 文件中的NORTHWNDConnectionString 设置。这个Web 应用程序是使用 Visual Studio 2005 Professional Edition 创建的基于文件系统的 Web 站点项目。不过,所有的这些教程同样适用于Visual Studio 2005 免费版,即 Visual Web Developer 。
该教程从头开始,先创建数据访问层 (DAL) ,然后在第二篇教程中创建业务逻辑层(BLL) ,并在第三篇教程中进行页面布局和导航。随后的教程以前三篇教程为基础。在这篇教程中我们有很多内容要学习,现在就让我们打开Visual Studio 开始吧!
步骤1 : 创建一个 Web 项目并连接到数据库
在创建我们的数据访问层 (DAL) 之前,我们首先需要创建一个网站并安装我们的数据库。开始创建一个新的基于文件系统的ASP.NET 网站:从 File 菜单选择 New Web Site ,出现 New Web Site 对话框。选择 ASP.NET Web Site 模板,将Location 下拉列表设置成 File System ,然后为该网站选择一个文件夹,并将语言设置成C# 。
图1 :创建一个基于文件系统的新网站
这将创建一个具有 Default.aspx ASP.NET 页面和 App_Data
文件夹的新网站。
创建好了网站,下一步是在 Visual Studio 的Server Explorer 中添加对该数据库的引用。通过在 Server Explorer 中添加数据库,您可以添加来自 Visual Studio 的表、存储过程、视图等。您还可以手动或通过Query Builder 直观地查看表数据或进行查询。而且,当我们为DAL 创建Typed DataSet 时,我们需要将 Visual Studio 指向需要建立 Typed DataSet 的数据库。当我们能够及时在那个点上提供这种连接信息时,Visual Studio 自动填充己在 Server Explorer 注册过的数据库的下拉列表。
将 Northwind 数据库添加到Server Explorer 的步骤取决于您是否使用App_Data 文件夹中的SQL Server 2005 Express Edition 数据库,或者是否有您想使用的Microsoft SQL Server 2000 或 2005 数据库服务器安装程序。
使用 App_Data 文件夹中的数据库
如果您没有 SQL Server 2000 或2005 数据库服务器可连接,或者您只想避免将该数据库添加到数据库服务器的麻烦,可以使用位于已下载网站源代码的App_Data 文件夹 中 的Northwind 数据库的 SQL Server 2005 Express Edition 版本(NORTHWND.MDF) 。
位于 App_Data 文件夹中的数据库将被自动添加到 Server Explorer 。假如您安装了SQL Server 2005 Express Edition ,在 Server Explorer 应该看到一个名为NORTHWND.MDF 的节点,可以展开并探究其表、视图、存储过程等(见图2 )。
App_Data 文件夹也可以存放 Microsoft Access .mdb 文件。同它们的 SQL Server 版本的数据库一样,这类文件将被自动添加到Server Explorer 。如果您不想使用任何 SQL Server 的数据库,您可以下载 Northwind 数据库文件的 Microsoft Access 版本 并加入 App_Data
目录。不过要记住,Access 数据库的特性不如SQL Server 丰富,且并不是为在网站环境下使用而设计的。另外,35 以后的教程将用到某些不被 Access 支持的数据库级特性。
连接到Microsoft SQL Server 2000 或2005 数据库服务器中的数据库
同样,您可能要连接到安装在数据库服务器上的Northwind 数据库。如果数据库服务器还没有安装Northwind 数据库,您必须先运行该教程下载文件中的安装脚本或直接从Microsoft 网站下载 Northwind 的 SQL Server 2000 版本和安装脚本 ,将其添加到数据库服务器。
一旦安装了该数据库,转到 Visual Studio 的Server Explorer ,右键单击 Data Connections 节点并选择 Add Connection 。如果没有找到 Server Explorer ,转入View / Server Explorer 或选择 Ctrl+Alt+S 。这时将出现 Add Connection 对话框,在这里可以指定要连接的服务器,认证信息和数据库名称。一旦成功配置了数据库连接信息,单击OK 按钮,该数据库将被作为一个节点添加到Data Connections 节点下面。您可以展开该数据库节点以探究其表、视图、存储过程等。
图2 :在您的数据库服务器的 Northwind 数据库添加一个连接
步骤2 :创建数据访问层
在处理数据时,有种做法是将数据的特定逻辑直接内嵌到表示层(Web 应用程序中,ASP.NET 页面组成表示层)。这可以通过在 ASP.NET 页面的代码部分编写 ADO.NET 代码,或者在标记符部分使用 SqlDataSource 控件来完成。无论采取哪种形式,该方法都让数据访问逻辑与表示层紧密结合。不过,建议将数据访问与表示层隔离开来。这个分离层被称作数据访问层(DAL) ,通常作为一个单独的类库项目来实现。这种分层体系结构的优势得到了很好的论述,我们在该系列教程中也采用了此法。
有关基础数据源的所有代码,如创建到数据库的连接,发出SELECT 、INSERT 、UPDATE 和DELETE 命令等,都应位于 DAL 。表示层不应包含对这些数据访问代码的任何引用,而是通过调用DAL 来实现所有的数据访问请求。数据访问层通常包含访问基础数据库数据的方法。例如,Northwind 数据库提供Products 和 Categories 表,记录要销售的产品及其他们所属的类别。我们的DAL 提供如下方法:
- GetCategories():返回所有类别的信息
- GetProducts():返回所有产品的信息
- GetProductsByCategoryID(categoryID):返回属于某一指定类别的所有产品
- GetProductByProductID(productID):返回某一产品的信息
调用时,这些方法将连接到数据库,进行适当的查询,并返回查询结果。重要的是返回这些结果的方式。这些方法可以简单返回一个由数据库查询填充的DataSet 或 DataReader ,但理想的是应使用强类型的对象来返回这些结果。强类型对象指的是编译时对其schema 进行严格定义的对象。相反,弱类型的对象指的是只有在运行时才知道其schema 的对象。
例如,DataReader 和DataSet (默认)是弱类型对象,因为它们的 schema 是由用来填充它们的数据库查询返回的列来定义的。要访问弱类型DataTable 中的某列,需要使用如下语法:DataTable.Rows[index]["columnName"] 。我们需要使用字符串或序号索引访问列名这一点就显示了该例中DataTable 的弱类型特性。另一方面,强类型的 DataTable 有各自作为属性实现的列,生成如下代码:DataTable.Rows[index].columnName。
要返回强类型对象,开发人员可以创建他们自己的自定义业务对象或使用Typed DataSet 。一个业务对象由开发人员实现成一个类,该类的属性通常反映出该业务对象表示的基础数据库表的列。Typed DataSet 是由 Visual Studio 基于数据库 schema 为您生成的一个类,其成员都是强类型的。Typed DataSet 本身包括了拓展ADO.NET DataSet 、DataTable 和 DataRow 类的类。除强类型 DataTable 外,Typed DataSet 现在还包括 TableAdapter ,该类具有填充 DataSet 的DataTable 以及将 DataTable 中所作修改传回数据库的方法。
注意:有关使用Typed DataSet 与自定义业务对象的优劣比较的更多信息,请参见设计数据层组件并在层间传递数据 。
我们对这些教程的体系结构使用强类型的DataSet 。图 3 说明了使用 Typed DataSet 的应用程序不同层间的工作流程。
图3 :所有的数据访问代码都在 DAL 中定义
创建一个 Typed DataSet 和Table Adapter
要创建我们的 DAL ,要先将一个Typed DataSet 添加到我们的项目。为此,右键单击 Solution Explorer 中的项目节点,并选择 Add a New Item 。从模板列表中选择DataSet 选项,并将其命名为Northwind.xsd 。
图4 :选择添加一个新的DataSet 到您的项目
单击 Add 后,出现提示添加DataSet 到App_Code 文件夹,选择Yes 。接着出现 Typed DataSet 设计器并将启动 TableAdapter Configuration Wizard ,允许您将您的第一个 TableAdapter 添加到 Typed DataSet 。
Typed DataSet 充当一个强类型的数据集;它由强类型的DataTable 实例组成,每个实例依次由强类型的 DataRow 实例组成。我们将为该教程系列所需的每个基础数据库表创建一个强类型的DataTable 。我们开始为Products 表创建 DataTable 。
要记住,强类型的 DataTable 不包含有关如何从其基础数据库表访问数据的任何信息。为了检索数据以填充DataTable ,我们使用一个 TableAdapter 类,作为我们的数据访问层。对于我们的Products 数据表,TableAdapter 将包含 GetProducts() 、GetProductByCategoryID(categoryID) 等方法,我们将从表示层调用它们。DataTable 的作用是充当用来在层间传送数据的强类型对象。
TableAdapter Configuration Wizard 从提示您选择要操作的数据库开始。下拉列表显示出Server Explorer 中的数据库。如果您没有把 Northwind 数据库添加到 Server Explorer ,此时单击 New Connection 按钮进行该操作。
图5 :从下拉列表中选择Northwind 数据库
选择了数据库单击 Next 后, 将会问您是否希望在Web.config 文件中保存连接字符串。保存了连接字符串,就避免了将连接字符串写在TableAdapter 类的代码中。这样一旦以后连接字符串信息改变,要做的工作也变得简单。如果选择将连接字符串保存到放在<connectionStrings> 区域的配置文件,以后可以通过 IIS GUI Admin Tool 内的新 ASP.NET 2.0 Property Page 选择加密 以改进安全性或修改。这样更适合管理员工作。
图6 :保存连接字符串到Web.config
接下来,我们需要为第一个强类型的DataTable 定义 schema ,并为我们的 TableAdapter 提供填充强类型的 DataSet 时所用到的第一个方法。通过创建一个查询,可同时完成这两个步骤,这个查询能够返回我们希望映射我们的DataTable 中的数据表的列。在向导结束时,我们将为该查询提供一个方法名称。完成后,就可以从我们的表示层调用该方法。此法将执行所定义的查询并填充强类型的DataTable 。
要开始定义 SQL 查询,就必须先说明希望 TableAdapter 进行查询的方式。我们可以使用一个 ad-hoc SQL 语句,创建一个新的存储过程,或使用现有的存储过程。对于本系列教程,我们将使用ad-hoc SQL 语句。有关使用存储过程的例子,请参见Brian Noyes 的文章:使用 Visual Studio 2005 DataSet Designer 构建一个数据访问层 。
图7 :使用ad-hoc SQL 语句查询数据
此时,我们可以手动输入 SQL 查询。在TableAdapter 创建第一个方法时,您通常希望查询返回需要在相应DataTable 中存放的那些列。这可以通过创建返回来自Products 表的所有列和行的查询实现:
图8 :在文本框输入SQL 查询
也可以使用 Query Builder 用图像构建查询,如图 9 所示。
图9 :通过Query Editor 用图像创建查询
创建查询之后,要在转到下一屏幕之前,单击Advanced Options 按钮。在 Web Site 项目中,“Generate Insert, Update, and Delete statements ”是默认选择的唯一高级选项;如果从Class Library 或Windows Project 运行该向导,“Use optimistic concurrency (使用并发优化)”选项将也被选中。现在暂不勾选该选项。我们将在以后的教程中详细介绍并发优化。
图10 :只选择“Generate Insert, Update, and Delete statements ”选项
核实了高级选项后,单击 Next 进入最后一个屏幕。这时会询问我们选择那些方法添加到TableAdapter 。填充数据的模式有两种:
- Fill a DataTable:通过这种途径创建的方法将 DataTable 作为一个参数,并根据查询结果对其进行填充。
例如,ADO.NET DataAdapter 类使用其 Fill()方法实现了该模式。 - Return a DataTable:通过这种途径创建的方法为您创建并填充DataTable ,并将
DataTable 作为方法的返回值。
您可以在 TableAdapter 实现这两种模式中的一种或两种。也可以重命名此处所提供的方法。即使我们在整个教程中只使用第二种模式,我们也可以同时选中两个复选框。并且将更通用的GetData
法重命名为GetProducts 。
如果选中最后一个复选框"GenerateDBDirectMethods" ,会为 TableAdapter 创建 Insert() 、Update() 和 Delete() 方法。如果没有选中该选项,所有的更新则需要通过TableAdapter 唯一的 Update() 方法进行,该方法接受 Typed DataSet 、DataTable 、单个DataRow 或 DataRow 数组。(如果没有选中图 9 高级选项中的"Generate Insert, Update, and Delete statements" 选项,该复选框的设置则不起作用。)在这里,我们勾选这个复选框。
图11 :将方法名称GetData 改为GetProducts
单击 Finish 结束向导。向导关闭后,返回到显示我们刚创建的DataTable 的 DataSet 设计器。可以看到Products 数据表中各列的列表(ProductID 、ProductName 等),以及ProductsTableAdapter 的方法(Fill() 和GetProducts() )。
图12 :Products DataTable 和ProductsTableAdapter 已被添加到Typed DataSet
这里,我们拥有一个带有单个 DataTable (Northwind.Products) 的Typed DataSet ,还有一个提供 GetProducts() 方法的强类型DataAdapter 类 (NorthwindTableAdapters.ProductsTableAdapter) 。这些对象可用来通过类似以下代码访问所有产品的列表:
1NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
2 new NorthwindTableAdapters.ProductsTableAdapter();
3Northwind.ProductsDataTable products;
4
5products = productsAdapter.GetProducts();
6
7 foreach (Northwind.ProductsRow productRow in products)
8 Response.Write("Product: " + productRow.ProductName + "<br />");
该代码不要求我们去编写任何针对数据访问的代码。我们不必生成任何ADO.NET 类的实例,不必指定任何连接字符串、SQL 查询或存储过程。TableAdapter 会为我们提供底层的数据访问代码。
本示例中所使用的每个对象都是强类型的,允许Visual Studio 提供 IntelliSense (智能感知)和编译时类型检查。而且,最好的是,TableAdapter 返回的DataTable 可以绑定到 ASP.NET Web 数据控件,如 GridView 、DetailsView 、DropDownList 、CheckBoxList 和其它。下面举例说明如何在Page_Load 事件处理程序仅用三行代码就将 GetProducts() 法返回的 DataTable 绑定到 GridView 。
AllProducts.aspx
1<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AllProducts.aspx.cs"
2 Inherits="AllProducts" %>
3
4<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
7<html xmlns="http://www.w3.org/1999/xhtml" >
8<head runat="server">
9 <title>View All Products in a GridView</title>
10 <link href="Styles.css" rel="stylesheet" type="text/css" />
11</head>
12<body>
13 <form id="form1" runat="server">
14 <div>
15 <h2>
16 All Products</h2>
17 <p>
18 <asp:GridView ID="GridView1" runat="server"
19 CssClass="DataWebControlStyle">
20 <HeaderStyle CssClass="HeaderStyle" />
21 <AlternatingRowStyle CssClass="AlternatingRowStyle" />
22 </asp:GridView>
23 </p>
24
25 </div>
26 </form>
27</body>
28</html>
AllProducts.aspx.cs
1 using System;
2 using System.Data;
3 using System.Configuration;
4 using System.Collections;
5 using System.Web;
6 using System.Web.Security;
7 using System.Web.UI;
8 using System.Web.UI.WebControls;
9 using System.Web.UI.WebControls.WebParts;
10 using System.Web.UI.HtmlControls;
11 using NorthwindTableAdapters;
12
13 public partial class AllProducts : System.Web.UI.Page
14 {
15 protected void Page_Load(object sender, EventArgs e)
16 {
17 ProductsTableAdapter productsAdapter = new
18 ProductsTableAdapter();
19 GridView1.DataSource = productsAdapter.GetProducts();
20 GridView1.DataBind();
21 }
22 }
图13 :显示在GridView 中的产品列表
尽管本例还需要我们在 ASP.NET 页面的 Page_Load 事件处理程序中编写三行代码,不过在以后的教程中我们将详细介绍如何使用ObjectDataSource ,用声明的方式获取 DAL 数据。使用 ObjectDataSource 我们不必编写代码也可以进行分页和排序!