创建业务逻辑层9030167617.docx

上传人:牧羊曲112 文档编号:2016598 上传时间:2022-12-31 格式:DOCX 页数:17 大小:216.98KB
返回 下载 相关 举报
创建业务逻辑层9030167617.docx_第1页
第1页 / 共17页
创建业务逻辑层9030167617.docx_第2页
第2页 / 共17页
创建业务逻辑层9030167617.docx_第3页
第3页 / 共17页
创建业务逻辑层9030167617.docx_第4页
第4页 / 共17页
创建业务逻辑层9030167617.docx_第5页
第5页 / 共17页
点击查看更多>>
资源描述

《创建业务逻辑层9030167617.docx》由会员分享,可在线阅读,更多相关《创建业务逻辑层9030167617.docx(17页珍藏版)》请在三一办公上搜索。

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

2、据交互中介的业务逻辑层 (BLL) 中。在真实的应用程序中,BLL 应作为一个单独的类库项目而实现。然而,为了简化项目结构,在这些教程中,我们以 App_Code 文件夹下的一系列的类来实现 BLL 。图 1 展示了表示层、BLL 和 DAL 之间的结构关系。图1 :BLL 将表示层与数据访问层分隔开来并且实施业务规则。步骤1 :创建 BLL 类我们的BLL 将由四个类组成,分别对应 DAL 中不同的 TableAdapter 。每个 BLL 类都具有一些方法,这些方法可以从 DAL 中该类对应的 TableAdapter 中检索、插入、更新或删除数据并应用相应的业务规则。为了更清楚地区分 D

3、AL 的相关类与 BLL 的相关类,我们在 App_Code 文件夹下创建两个子文件夹:DAL 和 BLL 。创建时,只需右健单击 Solution Explorer 中的 App_Code 文件夹并选择 New Folder 。创建了这两个文件夹后,将教程一中创建的 Typed DataSet 移动到 DAL 子文件夹中。然后,在BLL 子文件夹中创建四个 BLL 类文件。为此,右键单击 BLL 子文件夹,选择 Add a New Item ,然后选择 Class 模板。将这四个类分别命名为 ProductsBLL 、 CategoriesBLL 、 SuppliersBLL 和 Emplo

4、yeesBLL 。图2 :在App_Code 文件夹中添加四个新类接下来让我们在每个类中添加一些方法,这些方法只是简单地封装教程一中为TableAdapters 定义的方法。目前,这些方法只是对 DAL 中内容的直接调用,稍后我们会返回到这些方法中来添加任何所需的业务逻辑。注意:如果您当前使用的是Visual Studio Standard Edition 或以上版本 ( 即,当前使用的不是Visual Web Developer ),您可以使用Class Designer以可视的方式随意设计自己的类。有关 Visual Studio 中该新特性的详细信息,请参见Class Designer

5、Blog。对于ProductsBLL 类,总共需要添加七个方法 : GetProducts() 返回所有产品。 GetProductByProductID(productID) 返回具有指定产品 ID 的产品。 GetProductsByCategoryID(categoryID) 返回指定 种类 中的所有产品。 GetProductsBySupplier(supplierID) 返回来自指定供应商的所有产品。 AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, un

6、itsOnOrder, reorderLevel, discontinued) 通过传入值将一个新产品插入到数据库中 ; 返回新插入记录的 ProductID 值。 UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID) 通过传入值更新数据库中的一个现有产品 ; 如果正好更新了一行则返回 true , 否则返回 false 。 DeleteProduct(pro

7、ductID) 从数据库中删除指定产品。ProductsBLL.csusing System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using NorthwindTableAdapters;System.Com

8、ponentModel.DataObjectpublic class ProductsBLL private ProductsTableAdapter _productsAdapter = null; protected ProductsTableAdapter Adapter get if (_productsAdapter = null) _productsAdapter = new ProductsTableAdapter(); return _productsAdapter; System.ComponentModel.DataObjectMethodAttribute (System

9、.ComponentModel.DataObjectMethodType.Select, true) public Northwind.ProductsDataTable GetProducts() return Adapter.GetProducts(); System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Select, false) public Northwind.ProductsDataTable GetProductByProductID(int pr

10、oductID) return Adapter.GetProductByProductID(productID); System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Select, false) public Northwind.ProductsDataTable GetProductsByCategoryID(int categoryID) return Adapter.GetProductsByCategoryID(categoryID); System.C

11、omponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Select, false) public Northwind.ProductsDataTable GetProductsBySupplierID(int supplierID) return Adapter.GetProductsBySupplierID(supplierID); System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.Dat

12、aObjectMethodType.Insert, true) public bool AddProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit, decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel, bool discontinued) / Create a new ProductRow instance Northwind.ProductsDataTable pr

13、oducts = new Northwind.ProductsDataTable(); Northwind.ProductsRow product = products.NewProductsRow(); product.ProductName = productName; if (supplierID = null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value; if (categoryID = null) product.SetCategoryIDNull(); else product.C

14、ategoryID = categoryID.Value; if (quantityPerUnit = null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit; if (unitPrice = null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value; if (unitsInStock = null) product.SetUnitsInStockNull(); else product

15、.UnitsInStock = unitsInStock.Value; if (unitsOnOrder = null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value; if (reorderLevel = null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value; product.Discontinued = discontinued; / Add the new produ

16、ct products.AddProductsRow(product); int rowsAffected = Adapter.Update(products); / Return true if precisely one row was inserted, / otherwise false return rowsAffected = 1; System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, true) public bool UpdatePr

17、oduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit, decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel, bool discontinued, int productID) Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID); if (products.Count

18、 = 0) / no matching record found, return false return false; Northwind.ProductsRow product = products0; product.ProductName = productName; if (supplierID = null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value; if (categoryID = null) product.SetCategoryIDNull(); else product.

19、CategoryID = categoryID.Value; if (quantityPerUnit = null) product.SetQuantityPerUnitNull(); else product.QuantityPerUnit = quantityPerUnit; if (unitPrice = null) product.SetUnitPriceNull(); else product.UnitPrice = unitPrice.Value; if (unitsInStock = null) product.SetUnitsInStockNull(); else produc

20、t.UnitsInStock = unitsInStock.Value; if (unitsOnOrder = null) product.SetUnitsOnOrderNull(); else product.UnitsOnOrder = unitsOnOrder.Value; if (reorderLevel = null) product.SetReorderLevelNull(); else product.ReorderLevel = reorderLevel.Value; product.Discontinued = discontinued; / Update the produ

21、ct record int rowsAffected = Adapter.Update(product); / Return true if precisely one row was updated, / otherwise false return rowsAffected = 1; System.ComponentModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Delete, true) public bool DeleteProduct(int productID) int rows

22、Affected = Adapter.Delete(productID); / Return true if precisely one row was deleted, / otherwise false return rowsAffected = 1; 这些方法 GetProducts 、GetProductByProductID 、GetProductsByCategoryID 和 GetProductBySuppliersID ,只是返回数据,它们相当直接、简单,因为它们只是向下调用 DAL 中的内容。在一些场合下,可能会有一些业务规则需要在此层实现(例如基于当前已登录用户或用户所处职

23、位的授权规则,可以访问不同的数据),但在这里我们只是保留这些方法不变。因此,对于这些方法, BLL 只是充当了一个代理的作用,表示层通过这个代理来访问数据访问层中的底层数据。AddProduct 和 UpdateProduct 方法将产品各字段的值以参数形式传入,它们的作用分别是:添加一个新产品,更新一个现有产品。由于 Product 表的许多列,如 CategoryID 、 SupplierID 和 UnitPrice ,都可接受 NULL 值, AddProduct 和 UpdateProduct 中与这样的列相对应的输入参数使用nullable 类型。 Nullable 类型对于 .NE

24、T 2.0 来说是新类型,利用该类型所提供的技术,我们可以指示一个值类型是否可以是空类型。在 C# 中,可以通过在类型后加问号 ? 将一个值类型标记为 nullable 类型(例如 int? x; )。有关详情,请参见C# 编程指南中的Nullable 类型一节。这三个方法均返回布尔值,该值指示是否成功的插入、更新或删除了一行。返回该值的原因是,方法的操作并不一定会影响到一行。例如,如果页面开发人员调用 DeleteProduct 时传入的 ProductID 并非一个现有产品的 ID ,则发给数据库的 DELETE 语句不会产生任何影响,因而 DeleteProduct 方法会返回 fals

25、e。请注意,当添加一个新产品或更新一个现有产品时,我们将新的或更改的产品的字段值用一组数值传入,而不是为此接受一个ProductsRow 实例。选择该方式的原因是, ProductsRow 类派生于 ADO.NET DataRow 类,而后者并没有一个默认的无参数构造函数。为了创建一个新的 ProductsRow 实例,首先要创建一个 ProductsDataTable 实例,然后调用它的 NewProductRow() 方法(就像我们在AddProduct方法中作的那样)。当我们使用 ObjectDataSource 插入或更新产品时,其缺陷就会暴露出来。简言之, ObjectDataSou

26、rce 会尝试为输入的参数创建一个实例。如果 BLL 方法期待的是一个 ProductsRow 实例,则 ObjectDataSource 会尝试创建一个这样的实例,但是,由于缺少默认的无参数构造函数,该尝试失败。有关该问题的详细信息,请参见以下两个 ASP.NET 论坛:使用强类型DataSet 更新ObjectDataSources、ObjectDataSource 与强类型DataSet 的问题。另外,AddProduct 和 UpdateProduct 中的代码都会创建一个ProductsRow 实例并以刚传入的值对该实例进行赋值。当向 DataRow 的一些 DataColumn 赋

27、值时,可发生各种字段级的验证检查。因此,将传入的值进行一下人工的验证有助于确保传递给 BLL 方法的数据的有效性。不幸的是, Visual Studio 生成的强类型的 DataRow 类并不使用 nullable 类型。而为了给 DataRow 中的特定 DataColumn 赋数据库空值,我们必须使用 SetColumnNameNull() 方法。在UpdateProduct 中,我们 首先用 GetProductByProductID(productID) 载入要更新的产品。尽管这看似是一次不必要的对数据库的操作,在将来的介绍并发优化的教程中,该往返将会被证明是值得的。并发优化技术可确保

28、两个同时对同一数据进行操作的用户不会在不经意间覆盖彼此所作的更改。获取整个记录还使以下事情变得容易:在 BLL 中创建更新方法,使该方法只修改 DataRow 的所有列的一个子集。当我们研究 SuppliersBLL 类时,我们会看到这样一个例子。最后,请注意对ProductsBLL 类使用了DataObject 属性( 接近文件开头 , 类声明语句前面的 System.ComponentModel.DataObject 标签 ), 而其方法有DataObjectMethodAttribute属性。 DataObject 属性将该类标记为一个适合绑定到ObjectDataSource 控件的对

29、象,而 DataObjectMethodAttribute 属性则指示该方法的用途。在将来的教程中可以看到, ASP.NET 2.0 的 ObjectDataSource 使得以声明的方式从类中访问数据变得容易。默认情况下,在 ObjectDataSource 向导的下拉列表中只显示出标记为 DataObject 的那些类,这样有助于在该向导中筛选出可绑定的那些类。 ProductsBLL 类没有这些属性一样会工作良好,但是,加入这些属性可以使得在 ObjectDataSource 向导下的工作更为轻松。添加其它类在完成 ProductsBLL 类的编写后,我们还需要添加一些处理种类、供应商及

30、雇员数据的类。我们花一些时间用上面例子中的概念来创建下面的类和方法: CategoriesBLL.cso GetCategories()o GetCategoryByCategoryID(categoryID) SuppliersBLL.cso GetSuppliers()o GetSupplierBySupplierID(supplierID)o GetSuppliersByCountry(country)o UpdateSupplierAddress(supplierID, address, city, country) EmployeesBLL.cso GetEmployees()o G

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

32、entModel.DataObjectMethodAttribute (System.ComponentModel.DataObjectMethodType.Update, true)public bool UpdateSupplierAddress (int supplierID, string address, string city, string country) Northwind.SuppliersDataTable suppliers = Adapter.GetSupplierBySupplierID(supplierID); if (suppliers.Count = 0) /

33、 no matching record found, return false return false; else Northwind.SuppliersRow supplier = suppliers0; if (address = null) supplier.SetAddressNull(); else supplier.Address = address; if (city = null) supplier.SetCityNull(); else supplier.City = city; if (country = null) supplier.SetCountryNull();

34、else supplier.Country = country; / Update the supplier Address-related information int rowsAffected = Adapter.Update(supplier); / Return true if precisely one row was updated, / otherwise false return rowsAffected = 1; 步骤 2:通过 BLL 类访问 Typed DataSets在教程一中我们看到了直接使用 Typed DataSet 的编程例子。而现在我们已添加了一些 BLL

35、类,因此表示层应转而基于 BLL 而工作。教程一的AllProducts.aspx例子使用了ProductsTableAdapter来将产品列表绑定到一个 GridView,见下面的代码:ProductsTableAdapter productsAdapter = new ProductsTableAdapter();GridView1.DataSource = productsAdapter.GetProducts();GridView1.DataBind();要使用 BLL 类,只需改变代码的第一行 只需用ProductBLL对象代替ProductsTableAdapter对象:Produ

36、ctsBLL productLogic = new ProductsBLL();GridView1.DataSource = productLogic.GetProducts();GridView1.DataBind();也可以使用 ObjectDataSource 以声明的方式来访问BLL 类(如同 Typed DataSet )。我们将在后续教程中更为详细地讨论ObjectDataSource 。图3 :产品列表显示于GridView 中步骤3 :向 DataRow 类添加字段级验证字段级验证是进行插入或更新操作时针对业务对象的属性值而进行的检查。下面是对产品的一些字段级验证规则: Pro

37、ductName 字段的长度不能超过 40 个字符。 QuantityPerUnit 字段的长度不能超过 20 个字符。 ProductID 、ProductName 和 Discontinued 字段是必需的,但所有其它字段是可选的。 UnitPrice 、UnitsInStock 、UnitsOnOrder 和 ReorderLevel 字段必须大于等于零。这些规则可以并且应该在数据库级表达出来。Products 表的相应列的数据类型可反映对 ProductName 和 QuantityPerUnit 字段的字符数限制(分别为 nvarchar(40) 和nvarchar(20) )。对字

38、段是可选还是必需的表达是这样的:数据库表列允许还是不允许NULL 。四个检查约束的存在确保只有大于等于零的值才可赋值给UnitPrice 、UnitsInStock 、UnitsOnOrder 和 ReorderLevel 列。这些规则除了在数据库级实施外还应在DataSet 级实施。事实上,字段长度以及某值是必需的还是可选的,已被DataTable 的 DataColumn 集定义。要查看现有的自动提供的字段级验证,可转到DataSet 设计器,从其中一个DataTable 中选择一个域,然后转至 Properties 窗口。如图 4 所示,ProductsDataTable 中的 Quan

39、tityPerUnit DataColumn 允许的最大长度是 20 个字符,并且允许 NULL 值。如果我们试图将 ProductsDataRow 的 QuantityPerUnit 属性设置为一个超过 20 个字符的字符串值,系统会抛出 ArgumentException 异常 。图4 :DataColumn 提供基本域级验证不幸的是,我们不能通过 Properties 窗口指定边界检查,如,UnitPrice 必须大于等于零这样的检查。为了提供此类字段级验证,需要创建一个针对DataTable 的ColumnChanging事件的Event Handler。如前一教程所述,Typed D

40、ataSet 创建的 DataSet 、DataTables 和 DataRow 对象可以通过使用部分类来扩展。利用该技术我们可以为ProductsDataTable 类创建一个 ColumnChanging 事件的Event Handler。首先,在 App_Code 文件夹下创建一个名为 ProductsDataTable.ColumnChanging.cs 的类。图5 :在App_Code 文件夹中添加一个新类其次,创建一个针对 ColumnChanging 事件的Event Handler以确保UnitPrice 、UnitsInStock 、UnitsOnOrder 和 Reorde

41、rLevel 列的值(如果不是 NULL )大于等于零。其中任何一列超出范围,系统都会给出ArgumentException 。ProductsDataTable.ColumnChanging.cspublic partial class Northwind public partial class ProductsDataTable public override void BeginInit() this.ColumnChanging += ValidateColumn; void ValidateColumn(object sender, DataColumnChangeEventArg

42、s e) if(e.Column.Equals(this.UnitPriceColumn) if(!Convert.IsDBNull(e.ProposedValue) & (decimal)e.ProposedValue 0) throw new ArgumentException( UnitPrice cannot be less than zero, UnitPrice); else if (e.Column.Equals(this.UnitsInStockColumn) | e.Column.Equals(this.UnitsOnOrderColumn) | e.Column.Equal

43、s(this.ReorderLevelColumn) if (!Convert.IsDBNull(e.ProposedValue) & (short)e.ProposedValue 0) throw new ArgumentException(string.Format( 0 cannot be less than zero, e.Column.ColumnName), e.Column.ColumnName); 步骤 4:向 BLL 类添加定制的业务规则除了字段级验证外,可能还有高级定制的业务规则,这些规则涉及不同的实体,或者涉及到不能在单个列中表达的概念,例如: 如果一产品为断货 (discontinued) 产品,其 UnitPrice 就不能被更新。 雇员的居住国必须与其经理的居住国相同。 如果某产品是其供应商提供的唯一产品,该产品就不能为断货产品。BLL 类应含有检查,以确保遵守应用程序的业务规则。可将这

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号