创建数据访问层

本文档是 Visual Basic 教程 (切换到 Visual C# 教程)

该教程从头开始使用 Typed DataSet(强类型 DataSet)创建数据访问层 (DAL),以访问数据库中的信息。

« 前一篇教程  |  下一篇教程 »

步骤 3:向数据访问层添加带参数的方法

我们的 ProductsTableAdapter类此时有且只有一个方法:GetProducts()它返回数据库内的所有产品信息。尽管能够处理所有产品是肯定有用的,不过有时候我们希望只检索特定产品或属于某个类别的所有产品的信息。要在我们的数据访问层中添加这个功能,可以通过将带参数的方法添加到 TableAdapter 来实现。

现在我们添加GetProductsByCategoryID(categoryID)方法。向 DAL 添加一个新方法,返回到 DataSet Designer,右键单击ProductsTableAdapter区域,并选择 Add Query

图14: 右键单击 TableAdapter 并选择 Add Query

我们首先被问到是否希望使用 ad-hoc SQL 语句或创建或使用现有的存储过程来访问数据库。再次选择使用 ad-hoc SQL 语句。接下来会询问我们想使用的 SQL 查询类型。由于我们希望返回属于某一指定类别的所有产品信息,我们想编写一个返回行的SELECT 语句。

图15: 选择创建返回行的SELECT 语句

下一步是定义用来访问数据的 SQL 查询。由于我们希望只返回属于某一指定类别的那些产品信息,我使用的是GetProducts()中的同一个SELECT语句,但是添加了下面的WHERE子句:WHERE CategoryID = @CategoryID@CategoryID 参数向 TableAdapter 向导表明,我们正在创建的方法将要求一个对应类型的输入参数(也就是说,一个可为 Null 的整数)。

图16: 查询只返回指定类别中的产品信息

在最后一个步骤,我们可以选择要使用的数据访问模式,并自定义所生成方法的名称。将 Fill 模式重命名为FillByCategoryID,并使用GetProductsByCategoryID作为返回 DataTable 返回模式(GetX方法)的名称。

图 17: 为 TableAdapter 方法选择名称

向导结束后,DataSet 设计器包含新的 TableAdapter 方法。

图18: 产品现在可按类别进行查询

使用同样的技术再添加GetProductByProductID(productID)方法。

可以直接从 DataSet 设计器对这些带参数的查询进行检验。右键单击 TableAdapter 中的方法并选择 Preview Data。然后输入用于参数的值并单击 Preview。

图19: 显示出的属于饮料类别的产品信息

通过 DAL 中的GetProductsByCategoryID(categoryID)方法,我们现在可以创建一个只显示指定类别的那些产品的 ASP.NET 页面。下面举例显示 CategoryID为1 的饮料类别中的所有产品信息。

Beverages.aspx

<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Beverages.aspx.vb"
    Inherits="Beverages" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
    <link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>Beverages</h1>
        <p>
            <asp:GridView ID="GridView1" runat="server"
             CssClass="DataWebControlStyle">
               <HeaderStyle CssClass="HeaderStyle" />
               <AlternatingRowStyle CssClass="AlternatingRowStyle" />
            </asp:GridView>
             </p>
    </div>
    </form>
</body>
</html>

Beverages.aspx.vb

Imports NorthwindTableAdapters
Partial Class Beverages
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
        Handles Me.Load
        Dim productsAdapter As New ProductsTableAdapter
        GridView1.DataSource =
         productsAdapter.GetProductsByCategoryID(1)
        GridView1.DataBind()
    End Sub
End Class

图20: 显示出的饮料类别中的产品

步骤 4:数据的添加、更新和删除

添加、更新和删除数据的常用模式有两种。第一种模式,我称之为数据库直接模式,当涉及的方法调用时,会向数据库发送一个INSERT, UPDATEDELETE命令,该命令只对单个数据库记录进行操作。这些方法通常通过一系列的标量值(整数、字符串、布尔类型、DateTimes 等)来传递参数,这些值与要添加、更新或删除的值相对应。例如,采用这种模式对Products表进行操作,删除方法将采用一个整数参数,指明要删除的记录的ProductID,而添加法将对ProductName采用字符串,对UnitPrice采用十进制,对UnitsOnStock采用整数值等。

图21: 每个添加、更新和删除请求被立即送达数据库

我把另一种模式称为批量更新模式,就是在一次方法调用中更新整个 DataSet、DataTable、或 DataRows 集合。通过这种模式,开发人员在 DataTable 中删除、添加并修改 DataRow,然后将那些 DataRow 或 DataTable 传递给一个更新方法。该法随后列举传入的 DataRow,确定它们是否要进行修改、添加或删除(通过 DataRow 的 RowState property值),并为每条记录发出适当的数据库请求。

图22: 调用更新方法时,所有更改都和数据库保持同步

TableAdapter 默认采用的是批量更新模式,但也支持数据库直接模式。由于创建我们的 TableAdapter 时选择了 Advanced Properties 中的“Generate Insert, Update, and Delete statements”选项,所以ProductsTableAdapter包含一个实现批量更新模式的 Update()方法。具体点说,TableAdapter 包含Update() 方法,可以传入一个强类型的 DataTable,即 Typed DataSet,或一个或多个 DataRow 传递。如果您在首次创建 TableAdapter 时选中了“GenerateDBDirectMethods”复选框,数据库直接模式也可以通过Insert(), Update(), 和Delete() 方法来实现。

这两种数据修改模式都使用 TableAdapter 的InsertCommand, UpdateCommandDeleteCommand 属性来向数据库发布它们的INSERT, UPDATE, 和DELETE 命令。您可以通过单击 DataSet Designer 中的 TableAdapter 并转入 Properties 窗口来检查和修改 InsertCommand,UpdateCommand, 和 DeleteCommand属性。(要确信您已经选择了 TableAdapter 并确保ProductsTableAdapter 对象是 Properties 窗口中下拉列表中的被选中的选项。)

图23: TableAdapter 具有的InsertCommand, UpdateCommand, 和DeleteCommand 属性

要检查或修改这些数据库命令的任何属性,单击CommandText 子属性即可弹出 Query Builder。

图24: 在 Query Builder 配置INSERT, UPDATE, 和DELETE 语句

下面的代码示例说明了如何使用批量更新模式使所有没有断货的、 库存小于等于25件的产品的价格提高一倍:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim products As Northwind.ProductsDataTable = productsAdapter.GetProducts()
For Each product As Northwind.ProductsRow In products
   If Not product.Discontinued AndAlso product.UnitsInStock <= 25 Then
      product.UnitPrice *= 2
   End if
Next
productsAdapter.Update(products)

下面的代码表明如何使用数据库直接模式通过编码实现删除、更新某个产品,然后添加某个新产品:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
productsAdapter.Delete(3)
productsAdapter.Update( _
    "Chai", 1, 1, "10 boxes x 20 bags", 18.0, 39, 15, 10, false, 1)
productsAdapter.Insert( _
    "New Product", 1, 1, "12 tins per carton", 14.95, 15, 0, 10, false)

由数据库直接方法创建的Insert(),Update(),和 Delete()方法有点麻烦,尤其是对于那些有许多列的表。看前面的代码示例,没有 IntelliSense 的帮助, Products表的列与Update()Insert()方法的每个输入参数的映射关系就很不明显。有时候我们可能只想更新一个或两个列,或者需要一个自定义Insert()方法,该法可能返回新添加记录的IDENTITY (自动递增)字段的值。

要创建这样的自定义方法,返回到 DataSet Designer。右键单击 TableAdapter 并选择 Add Query,返回 TableAdapter 向导。在第二个屏幕上,我们可以指明要创建的查询类型。现在我们创建一个添加新产品并返回新加记录的ProductID的值的方法。因此,选择创建一个INSERT 查询。

Figure 25: 创建一个向Products 表添加新行的方法

下一个屏幕上出现 InsertCommandCommandText 。在查询末尾添加SELECT SCOPE_IDENTITY()语句,这样将返回同一范围内添加到IDENTITY 列的最后一个 identity 值。(参见 技术文档技术文档SCOPE_IDENTITY()的更多信息以及您可能希望 使用 SCOPE_IDENTITY() 代替 @@IDENTITY。) 确保您在添加SELECT 语句之前用一个分号结束INSERT 语句。

图26: 增大返回SCOPE_IDENTITY() 值的查询范围

最后,将新方法命名为InsertProduct

图27: 设置新方法的名称为 InsertProduct

当您返回到 DataSet 设计器时,您会发现ProductsTableAdapter 包含了新方法:InsertProduct。如果对应Products表中的每个列,这个新方法没有对应的参数,可能就是您忘记用分号来终止INSERT 语句。配置InsertProduct方法并确保您使用了分号来终止 INSERTSELECT 语句。

默认状态下,添加方法调用的是非查询方法,意味着它们返回的是受影响的行数。 不过,我们希望 InsertProduct方法返回查询返回的值,而不是受影响的行数。 为此,将 InsertProduct 方法的ExecuteMode 的属性修改为Scalar.

图28: 将ExecuteMode 属性更改为Scalar

下面的代码表明了运行中的这个新的InsertProduct 方法:

Dim productsAdapter As New NorthwindTableAdapters.ProductsTableAdapter()
Dim new_productID As Integer = Convert.ToInt32(productsAdapter.InsertProduct( _
    "New Product", 1, 1, "12 tins per carton", 14.95, 10, 0, 10, false))
productsAdapter.Delete(new_productID)





上一页 | 1 | 2 | 3 | 下一页