创建业务逻辑层

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

本教程中,我们将了解怎样将业务规则集中到在表示层与 DAL 之间,充当数据交互中介的业务逻辑层 (BLL) 中。

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

简介

在教程一中创建的数据访问层 (DAL) 将数据访问逻辑与表示逻辑清晰地分离开来。然而,尽管 DAL 从表示层中清晰地分离出数据访问层细节,它却并没有实施任何可能采用的业务规则。例如,我们想让我们的应用程序在Discontinued 字段设为 1 时禁止对Products 表的 CategoryIDSupplierID字段的修改,还有,我们可能想实施一些资历规则以便禁止发生这样的情况:雇员被其后入职的另一雇员所管理。另一种常见的情形是授权 – 可能只有处于特定职位的用户可以删除产品或更改UnitPrice 值。

通过本教程,我们可以了解怎样将业务规则集中到在表示层与 DAL 之间充当数据交互中介的业务逻辑层 (BLL) 中。在真实的应用程序中,BLL 应作为一个单独的类库项目而实现。然而,为了简化项目结构,在这些教程中,我们以App_Code 文件夹下的一系列的类来实现 BLL。图 1 展示了表示层、BLL 和 DAL 之间的结构关系。

图1: BLL 将表示层与数据访问层分隔开来并且实施业务规则。

我们不采用创建单独类实现 业务逻辑的方法,而是选择将该逻辑直接放在有部分类的 Typed DataSet中。有关创建和扩展 Typed DataSet 的示例,请向前参考教程一。

步骤 1:创建 BLL 类

我们的 BLL将由四个类组成,分别对应 DAL中不同的 TableAdapter.。每个BLL类都具有一些方法,这些方法可以从DAL 中该类对应的TableAdapter中检索、插入、更新或删除数据并应用相应的业务规则。

为了更清楚地区分 DAL 的相关类与 BLL 的相关类,我们在 App_Code文件夹下创建两个子文件夹:DAL 和 BLL。创建时,只需右健单击 Solution Explorer 中的App_Code 文件夹并选择 New Folder。创建了这两个文件夹后,将教程一中创建的Typed DataSet 移动到 DAL 子文件夹中。

然后,在 BLL 子文件夹中创建四个 BLL 类文件。为此,右键单击 BLL 子文件夹,选择 Add a New Item,然后选择 Class 模板。将这四个类分别命名为ProductsBLL, CategoriesBLL,SuppliersBLLEmployeesBLL

图2: 在 App_Code文件夹中添加四个新类

接下来让我们在每个类中添加一些方法,这些方法只是简单地封装教程一中为 TableAdapters 定义的方法。目前,这些方法只是对 DAL 中内容的直接调用,稍后我们会返回到这些方法中来添加任何所需的业务逻辑。

注意:如果您当前使用的是 Visual Studio Standard Edition 或以上版本(即,当前使用的是 Visual Web Developer),您可以使用 Class Designer,以可视的方式随意设计自己的类。有关 Visual Studio 中该新特性的详细信息,请参见 Class Designer Blog

对于 ProductsBLL类,总共需要添加七个方法:

  • GetProducts() – 返回所有产品
  • GetProductByProductID(productID) – 返回具有指定产品 ID 的产品
  • GetProductsByCategoryID(categoryID)– 返回指定种类中的所有产品
  • GetProductsBySupplier(supplierID) – 返回来自指定供应商的所有产品。
  • AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued) – 通过传入值将一个新产品插入到数据库中;返回新插入记录的ProductID
  • UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID) – 通过传入值更新数据库中的一个现有产品;如果正好更新了一行则返回为True,否则返回为 False
  • DeleteProduct(productID) – 从数据库中删除指定产品

ProductsBLL.vb

Imports NorthwindTableAdapters
<System.ComponentModel.DataObject()> _
Public Class ProductsBLL
    Private _productsAdapter As ProductsTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As ProductsTableAdapter
        Get
            If _productsAdapter Is Nothing Then
                _productsAdapter = New ProductsTableAdapter()
            End If
            Return _productsAdapter
        End Get
    End Property
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetProducts() As Northwind.ProductsDataTable
        Return Adapter.GetProducts()
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, False)> _
    Public Function GetProductByProductID(ByVal productID As Integer) _
        As Northwind.ProductsDataTable
        Return Adapter.GetProductByProductID(productID)
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, False)> _
    Public Function GetProductsByCategoryID(ByVal categoryID As Integer) _
        As Northwind.ProductsDataTable
        Return Adapter.GetProductsByCategoryID(categoryID)
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, False)> _
    Public Function GetProductsBySupplierID(ByVal supplierID As Integer) _
        As Northwind.ProductsDataTable
        Return Adapter.GetProductsBySupplierID(supplierID)
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Insert, True)> _
    Public Function AddProduct( _
        productName As String, supplierID As Nullable(Of Integer), _
        categoryID As Nullable(Of Integer), quantityPerUnit As String, _
        unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
        unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
        discontinued As Boolean) _
        As Boolean
        Dim products As New Northwind.ProductsDataTable()
        Dim product As Northwind.ProductsRow = products.NewProductsRow()
        product.ProductName = productName
        If Not supplierID.HasValue Then
            product.SetSupplierIDNull()
        Else
            product.SupplierID = supplierID.Value
        End If
        If Not categoryID.HasValue Then
            product.SetCategoryIDNull()
        Else
            product.CategoryID = categoryID.Value
        End If
        If quantityPerUnit Is Nothing Then
            product.SetQuantityPerUnitNull()
        Else
            product.QuantityPerUnit = quantityPerUnit
        End If
        If Not unitPrice.HasValue Then
            product.SetUnitPriceNull()
        Else
            product.UnitPrice = unitPrice.Value
        End If
        If Not unitsInStock.HasValue Then
            product.SetUnitsInStockNull()
        Else
            product.UnitsInStock = unitsInStock.Value
        End If
        If Not unitsOnOrder.HasValue Then
            product.SetUnitsOnOrderNull()
        Else
            product.UnitsOnOrder = unitsOnOrder.Value
        End If
        If Not reorderLevel.HasValue Then
            product.SetReorderLevelNull()
        Else
            product.ReorderLevel = reorderLevel.Value
        End If
        product.Discontinued = discontinued
        products.AddProductsRow(product)
        Dim rowsAffected As Integer = Adapter.Update(products)
        Return rowsAffected = 1
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Update, True)> _
    Public Function UpdateProduct(_
        productName As String, supplierID As Nullable(Of Integer), _
        categoryID As Nullable(Of Integer), quantityPerUnit As String, _
        unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
        unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
        discontinued As Boolean, productID As Integer) _
        As Boolean
        Dim products As Northwind.ProductsDataTable = _
            Adapter.GetProductByProductID(productID)
        If products.Count = 0 Then
            Return False
        End If
        Dim product as Northwind.ProductsRow = products(0)
        product.ProductName = productName
        If Not supplierID.HasValue Then
            product.SetSupplierIDNull()
        Else
            product.SupplierID = supplierID.Value
        End If
        If Not categoryID.HasValue Then
            product.SetCategoryIDNull()
        Else
            product.CategoryID = categoryID.Value
        End If
        If quantityPerUnit Is Nothing Then
            product.SetQuantityPerUnitNull()
        Else
            product.QuantityPerUnit = quantityPerUnit
        End If
        If Not unitPrice.HasValue Then
            product.SetUnitPriceNull()
        Else
            product.UnitPrice = unitPrice.Value
        End If
        If Not unitsInStock.HasValue Then
            product.SetUnitsInStockNull()
        Else
            product.UnitsInStock = unitsInStock.Value
        End If
        If Not unitsOnOrder.HasValue Then
            product.SetUnitsOnOrderNull()
        Else
            product.UnitsOnOrder = unitsOnOrder.Value
        End If
        If Not reorderLevel.HasValue Then
            product.SetReorderLevelNull()
        Else
            product.ReorderLevel = reorderLevel.Value
        End If
        product.Discontinued = discontinued
        Dim rowsAffected As Integer = Adapter.Update(product)
        Return rowsAffected = 1
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Delete, True)> _
    Public Function DeleteProduct(ByVal productID As Integer) As Boolean
        Dim rowsAffected As Integer = Adapter.Delete(productID)
        Return rowsAffected = 1
    End Function
End Class

这些方法 – GetProducts,GetProductByProductID,GetProductsByCategoryIDGetProductBySuppliersID – ,只是返回数据,它们相当直接简单,因为它们只是向下调用 DAL 中的内容。在一些场合下,可能会有一些业务规则需要在此层实现(例如基于当前已登录用户或用户所处职位的授权规则,可以访问不同的数据),但在这里我们只是保留这些方法不变。因此,对于这些方法,BLL 只是充当了一个代理的作用,表示层通过这个代理来访问数据访问层中的底层数据。

AddProductUpdateProduct方法将产品各字段的值以参数形式传入,它们的作用分别是: 添加一个新产品,更新一个现有产品。由于Product 表的许多列,如CategoryIDSupplierID 和 UnitPrice, 都可接受 NULL值,AddProductUpdateProduct中与这样的列相对应的输入参数使用 Nullable 类型。Nullable 类型对于 .NET 2.0 来说是新类型,利用该类型所提供的技术,我们可以指示一个值类型是否可以是空类型。有关Nullable结构的更多信息,请参考 Paul Vick的博客文章The Truth About Nullable Types and VB 和技术文档。

这三个方法均返回布尔值,该值指示是否成功的插入、更新或删除了一行。返回该值的原因是, 方法的操作并不一定会影响到一行。例如,如果页面开发人员调用DeleteProduct 时传入的ProductID 并非一个现有产品的 ID,则发给数据库的 DELETE语句不会产生任何影响, 因而DeleteProduct 方法会返回False

请注意,当添加一个新产品或更新一个现有产品时,我们将新的或更改的产品的字段值当作一组数值传入, 而不是为此接受一个 ProductsRow实例。选择该方式的原因是,ProductsRow类派生于 ADO.NET DataRow 类, 而后者并没有一个默认的无参构造函数。为了创建一个新的ProductsRow 实例,首先要创建一个ProductsDataTable 实例,然后调用它的NewProductRow() 方法(就像我们在AddProduct 方法中作的那样)。 当我们使用 ObjectDataSource 插入或更新产品时,其缺陷就会暴露出来。简言之, ObjectDataSource 会尝试为输入参数创建一个实例。如果 BLL 方法期待的是一个 ProductsRow 实例, 则 ObjectDataSource 会尝试创建一个这样的实例,但是,由于缺少默认的无参数构造函数,该尝试失败。 有关该问题的详细信息,请参见以下两个 ASP.NET 论坛: Updating ObjectDataSources with Strongly-Typed DataSetsProblem With ObjectDataSource and Strongly-Typed DataSet

另外,AddProductUpdateProduct 中的代码都会创建一个ProductsRow实例并以刚传入的值对该实例进行赋值。当向 DataRow 的一些 DataColumn 赋值时, 可发生各种字段级的验证检查。因此,将传入的值进行人工的验证有助于确保传递给 BLL 方法的数据的有效性。不幸的是,Visual Studio 生成的强类型的 DataRow 类并不使用 nullable 类型。 而为了给 DataRow 中的特定 DataColumn赋数据库空值,我们必须使用SetColumnNameNull() 方法。

UpdateProduct 中,我们首先用GetProductByProductID(productID)载入要更新的产品。尽管这看似是一次不必要的对数据库的操作,在将来的介绍并行优化的教程中,该往返将会被证明是值得的。并行优化技术可确保两个同时对同一数据进行操作的用户不会在不经意间覆盖彼此所作的更改。获取整个记录还使以下事情变得容易:在 BLL 中创建更新方法,使该方法只修改DataRow 的所有列的一个子集。当我们研究SuppliersBLL类时,我们会看到这样一个例子。

最后,请注意对 ProductsBLL 类使用了DataObject 属性(接近文件开头,类声明语句前面的[System.ComponentModel.DataObject]标签),而其方法有 DataObjectMethodAttribute 属性DataObject属性将该类标记为一个适合绑定到 ObjectDataSource control的对象,而DataObjectMethodAttribute属性则指示该方法的用途。在将来的教程中可以看到,ASP.NET 2.0 的 ObjectDataSource 使得以声明的方式从类中访问数据变得容易。默认情况下,在 ObjectDataSource 向导的下拉列表中只显示出标记为DataObject的那些类,这样有助于在该向导中筛选出可绑定到的那些类。ProductsBLL类没有这些属性一样会工作良好,但是,加入这些属性可以使得在ObjectDataSource向导下的工作更为轻松。

添加其它类

在完成 ProductsBLL类的编写后,我们还需要添加一些处理种类、供应商及雇员数据的类。我们花一些时间用上面例子中的概念来创建下面的类和方法:

  • CategoriesBLL.cs
    • GetCategories()
    • GetCategoryByCategoryID(categoryID)
  • SuppliersBLL.cs
    • GetSuppliers()
    • GetSupplierBySupplierID(supplierID)
    • GetSuppliersByCountry(country)
    • UpdateSupplierAddress(supplierID,address, city,country)
  • EmployeesBLL.cs
    • GetEmployees()
    • GetEmployeeByEmployeeID(employeeID)
    • GetEmployeesByManager(managerID)

值得注意的一个方法是 SuppliersBLL类的 UpdateSupplierAddress 方法。 该方法提供了一个接口以便只更新供应商的地址信息。在内部实现上,该方法读取指定supplierIDSupplierDataRow对象(使用 GetSupplierBySupplierID来读取), 设置其相关地址属性,然后向下调用SupplierDataTable的更新方法。UpdateSupplierAddress方法如下:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateSupplierAddress(ByVal supplierID As Integer, _
    ByVal address As String, ByVal city As String, ByVal country As String) _
    As Boolean
    Dim suppliers As Northwind.SuppliersDataTable = _
        Adapter.GetSupplierBySupplierID(supplierID)
    If suppliers.Count = 0 Then
        Return False
    Else
        Dim supplier As Northwind.SuppliersRow = suppliers(0)
        If address Is Nothing Then
            supplier.SetAddressNull()
        Else
            supplier.Address = address
        End If
        If city Is Nothing Then
            supplier.SetCityNull()
        Else
            supplier.City = city
        End If
        If country Is Nothing Then
            supplier.SetCountryNull()
        Else
            supplier.Country = country
        End If
        Dim rowsAffected As Integer = Adapter.Update(supplier)
        Return rowsAffected = 1
    End If
End Function

步骤 2:通过 BLL 类访问 Typed DataSets

在教程一中我们看到了直接使用 Typed DataSet 的编程例子。而现在我们已添加了一些 BLL 类,因此表示层应转而基于 BLL 而工作。教程一的 AllProducts.aspx 例子使用了 ProductsTableAdapter 来将产品列表绑定到一个 GridView,见下面的代码:

Dim productsAdapter As New ProductsTableAdapter()
    GridView1.DataSource = productsAdapter.GetProducts() 
    GridView1.DataBind()

要使用 BLL 类,只需改变代码的第一行 – 只需用 ProductBLL 对象代替 ProductsTableAdapter 对象:

Dim productLogic As New ProductsBLL()
GridView1.DataSource = productLogic.GetProducts()
GridView1.DataBind()

也可以使用 ObjectDataSource 以声明的方式来访问 BLL 类(如同 Typed DataSet)。我们将在后续教程中更为详细地讨论 ObjectDataSource。

图3: 产品列表显示于 GridView 中

步骤 3:向 DataRow 类添加字段级验证

字段级验证是进行插入或更新操作时针对业务对象的属性值而进行的检查。下面是对产品的一些字段级验证规则:

  • ProductName 字段的长度不能超过 40 个字符
  • QuantityPerUnit 字段的长度不能超过 20 个字符
  • ProductID, ProductNameDiscontinued字段是必需的,但所有其它字段是可选的
  • UnitPrice, UnitsInStock,UnitsOnOrder, 和 ReorderLevel字段必须大于等于零

T这些规则可以并且应该在数据库级表达出来。Products 表的相应列的数据类型可反映对 ProductName 和 QuantityPerUnit 字段的字符数限制(分别为 nvarchar(40) 和 nvarchar(20))。对字段是可选还是必需的表达是这样的:数据库表列允许还是不允许 NULL。四个 check constraints的存在确保只有大于等于零的值才可赋值给UnitPrice、UnitsInStock、UnitsOnOrder 和 ReorderLevel 列。

这些规则除了在数据库级实施外还应在 DataSet 级实施。事实上,域长度,以及某值是必需的还是可选的,已被 DataTable 的 DataColumn 集所捕获。要查看现有的自动提供的域级验证,可转到 DataSet Designer,从其中一个 DataTable 中选择一个域,然后转至 Properties 窗口。如图 4 所示,ProductsDataTable 中的 QuantityPerUnit DataColumn 允许的最大长度是 20 个字符,并且允许 NULL 值。如果我们试图将 ProductsDataRow 的 QuantityPerUnit 属性设置为一个超过 20 个字符的字符串值,系统会抛出 ArgumentException异常。

图4: DataColumn 提供基本域级验证

不幸的是,我们不能通过 Properties 窗口指定边界检查,如,UnitPrice 必须大于等于零这样的检查。为了提供此类字段级验证,需要创建一个针对 DataTable 的 ColumnChanging 事件的Event Handler。如 前一教程所述,Typed DataSet 创建的 DataSet、DataTables 和 DataRow 对象可以通过使用部分类来扩展。利用该技术我们可以为 ProductsDataTable 类创建一个 ColumnChanging Event Handler。首先,在 App_Code 文件夹下创建一个名为 ProductsDataTable.ColumnChanging.vb 的类。

图5: 在App_Code 文件夹中添加一个新类

其次,创建一个针对 ColumnChanging 事件的Event Handler以确保 UnitPrice、UnitsInStock、UnitsOnOrder 和 ReorderLevel 列的值(如果不是 NULL)大于等于零。其中任何一列超出范围,系统都会给出 ArgumentException。

ProductsDataTable.ColumnChanging.vb

Imports System.data
Partial Public Class Northwind
    Partial Public Class ProductsDataTable
        Public Overrides Sub BeginInit()
            AddHandler Me.ColumnChanging, AddressOf ValidateColumn
        End Sub
        Sub ValidateColumn(sender As Object, e As DataColumnChangeEventArgs)
            If e.Column.Equals(Me.UnitPriceColumn) Then
                If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
                    CType(e.ProposedValue, Decimal) < 0 Then
                    Throw New ArgumentException( _
                        "UnitPrice cannot be less than zero", "UnitPrice")
                End If
            ElseIf e.Column.Equals(Me.UnitsInStockColumn) OrElse _
                e.Column.Equals(Me.UnitsOnOrderColumn) OrElse _
                e.Column.Equals(Me.ReorderLevelColumn) Then
                If Not Convert.IsDBNull(e.ProposedValue) AndAlso _
                    CType(e.ProposedValue, Short) < 0 Then
                    Throw New ArgumentException(String.Format( _
                        "{0} cannot be less than zero", e.Column.ColumnName), _
                        e.Column.ColumnName)
                End If
            End If
        End Sub
    End Class
End Class

步骤 4:向 BLL 类添加定制的业务规则

除了字段级验证外,可能还有高级定制的业务规则,这些规则涉及不同的实体,或者涉及到不能在单个列中表达的概念,例如:

  • 如果一产品为断货 (discontinued) 产品,其 UnitPrice 就不能被更新。
  • 雇员的居住国必须与其经理的居住国相同。
  • 如果某产品是其供应商提供的唯一产品,该产品就不能为断货产品。

BLL 类应含有检查,以确保遵守应用程序的业务规则。可将这些检查直接添加到它们所应用到的方法中。

假设我们的业务规则规定:如果某产品是指定供应商的唯一产品,该产品就不能标记为 discontinued。即,如果产品 X 是我们从供应商 Y 处购买的唯一产品,我们就不能将 X 标记为 discontinued;但是如果供应商 Y 为我们提供了三个产品:A、B 和 C,那么我们可将其中任何一个或所有的标记为 discontinued。这是一个奇怪的业务规则,但业务规则并不总是符合一般常识!

为了对 UpdateProducts 方法实施此业务规则,我们首先检查 Discontinued 是否设置为 True,如是,我们会调用 GetProductsBySupplierID 来确定我们从该产品的供应商处购买了多少个产品。如果从该供应商处只购买了一个产品,我们抛出 ApplicationException异常。

<System.ComponentModel.DataObjectMethodAttribute_
    (System.ComponentModel.DataObjectMethodType.Update, True)> _
Public Function UpdateProduct( _
    productName As String, supplierID As Nullable(Of Integer), _
    categoryID As Nullable(Of Integer), quantityPerUnit As String, _
    unitPrice As Nullable(Of Decimal), unitsInStock As Nullable(Of Short), _
    unitsOnOrder As Nullable(Of Short), reorderLevel As Nullable(Of Short), _
    discontinued As Boolean, productID As Integer) _
    As Boolean
    Dim products As Northwind.ProductsDataTable = _
        Adapter.GetProductByProductID(productID)
    If products.Count = 0 Then
        Return False
    End If
    Dim product As Northwind.ProductsRow = products(0)
    If discontinued Then
        Dim productsBySupplier As Northwind.ProductsDataTable = _
            Adapter.GetProductsBySupplierID(product.SupplierID)
        If productsBySupplier.Count = 1 Then
            Throw New ApplicationException( _
                "You cannot mark a product as discontinued if it is " & _
                "the only product purchased from a supplier")
        End If
    End If
    product.ProductName = productName
    If Not supplierID.HasValue Then
        product.SetSupplierIDNull()
    Else
        product.SupplierID = supplierID.Value
    End If
    If Not categoryID.HasValue Then
        product.SetCategoryIDNull()
    Else
        product.CategoryID = categoryID.Value
    End If
    If quantityPerUnit Is Nothing Then
        product.SetQuantityPerUnitNull()
    Else
        product.QuantityPerUnit = quantityPerUnit
    End If
    If Not unitPrice.HasValue Then
        product.SetUnitPriceNull()
    Else
        product.UnitPrice = unitPrice.Value
    End If
    If Not unitsInStock.HasValue Then
        product.SetUnitsInStockNull()
    Else
        product.UnitsInStock = unitsInStock.Value
    End If
    If Not unitsOnOrder.HasValue Then
        product.SetUnitsOnOrderNull()
    Else
        product.UnitsOnOrder = unitsOnOrder.Value
    End If
    If Not reorderLevel.HasValue Then
        product.SetReorderLevelNull()
    Else
        product.ReorderLevel = reorderLevel.Value
    End If
    product.Discontinued = discontinued
    Dim rowsAffected As Integer = Adapter.Update(product)
    Return rowsAffected = 1
End Function

在表示层对验证错误进行响应

从表示层调用 BLL 时,我们可以决定是尝试对任何可能出现的异常情况进行处理,还是让这些异常直接抛给 ASP.NET(它们会引发HttpApplication 的错误事件)。要在编程使用 BLL时处理一个异常,我们可以使用 Try...Catch块,如下所示:

Dim productLogic As New ProductsBLL()
Try
    productLogic.UpdateProduct("Scotts Tea", 1, 1, Nothing, _
      -14, 10, Nothing, Nothing, False, 1)
Catch ae As ArgumentException
    Response.Write("There was a problem: " & ae.Message)
End Try

在以后的教程中我们会看到,当使用一个 Web 数据控件来插入、更新或删除数据时,可以通过一个Event Handler对从 BLL抛出的异常进行处理而不用将该处理代码封装于 Try...Catch 块中。

小结

一个结构良好的应用程序都有清晰的层次结构,每层都封装有特定的任务。在本系列文章的第一篇教程中,我们用 Typed DataSets 创建了一个数据访问层;在本教程中,我们建立了一个业务逻辑层,该层包括我们的应用程序的 App_Code 文件夹下的一系列类,这些类向下调用 DAL 中的内容。我们的应用程序通过 BLL 实现了字段级和业务级逻辑。在本教程中,我们创建了一个独立的 BLL,除此之外的另一个选择是,利用部分类来扩展 TableAdapters 的方法。但是,使用这一技术,我们并不能重写现有的方法,也不能象本文中采用的方式一样清晰地分隔开我们的 DAL 和 BLL。

完成 DAL 和 BLL 的代码编写后,我们就可以着手编写我们的表示层代码了。在下一教程 中,我们会短暂地偏离数据访问主题,转而去定义一个将为所有教程所使用的一致的页面布局。

快乐编程!





下一篇教程