ASP.NET 2.0數(shù)據(jù)教程:創(chuàng)建BLL類
在ASP.NET 2.0中,我們其實可以將業(yè)務(wù)邏輯層(Business Logic Layer,以下簡稱BLL)看作是在數(shù)據(jù)訪問層和表示層之間進(jìn)行數(shù)據(jù)交換的橋梁,在這個章節(jié)中,我們將討論一下如何將這些業(yè)務(wù)規(guī)則集成到一個BLL中。需要說明的是,在一個實際的應(yīng)用程序中,BLL都是以類庫(Class Library)的形式來實現(xiàn)的,不過為了簡化工程的結(jié)構(gòu),在本教程中我們將BLL實現(xiàn)為App_Code文件夾中的一系列的類。圖一向我們展示了表示層、BLL以及DAL三者之間的結(jié)構(gòu)關(guān)系。
圖一:BLL將表示層與DAL隔開了,并且加入了業(yè)務(wù)規(guī)則
***步:創(chuàng)建BLL類
我們的BLL由4個類組成,每一個BLL類都對應(yīng)DAL中的一個TableAdapter,它們都從各自的TableAdapter中得到讀取、插入、修改以及刪除等方法以應(yīng)用合適的業(yè)務(wù)規(guī)則。
為了更加清晰的區(qū)分DAL和BLL的類,我們在App_Code文件夾中建立兩個子文件夾,分別命名為DAL和BLL。你僅僅需要在解決方案瀏覽器(Solution Explorer)中右鍵點擊App_Code文件夾,并選擇新建文件夾(New Folder),就可以創(chuàng)建新的子文件夾了。建好了這兩個文件夾之后,把***節(jié)中所創(chuàng)建的類型化數(shù)據(jù)集(Typed DataSet)移到DAL文件夾中。
然后,在BLL文件夾中創(chuàng)建4個類文件。同樣,你僅僅需要在解決方案瀏覽器(Solution Explorer)中右鍵點擊BLL文件夾,并選擇新建項目(New Item),然后在彈出的對話框中選擇類模板(Class template)就可以創(chuàng)建新的類文件了。將這四個文件分別命名為ProductsBLL、CategoriesBLL、SuppliersBLL以及EmployeesBLL。
圖二:在BLL文件夾中添加4個新的類
接下來,讓我們來給這些新建的類加上一些方法,簡單的將***節(jié)中的TableAdapter中的那些方法包裝起來就行了?,F(xiàn)在,這些方法將只能直接使用DAL中的那些方法,我們等會再來給他們加上一些業(yè)務(wù)邏輯。
注意:如果你使用的是Visual Studio 標(biāo)準(zhǔn)版或以上版本(也就是說,你不是用的Visual Web Developer),那么你還可以使用Class Designer來可視化的設(shè)計你的類。你可以在Class Designer Blog上得到關(guān)于Visual Studio的這項新功能的詳細(xì)信息。
在ProductsBLL類中,我們一共需要為其添加7個方法:
l GetProducts() – 返回所有的產(chǎn)品
l GetProductByProductID(productID) – 返回指定ProductID的產(chǎn)品
l GetProductsByCategoryID(categoryID) –返回指定分類的產(chǎn)品
l GetProductsBySupplier(supplierID) –返回指定供應(yīng)商的產(chǎn)品
l AddProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued) – 向數(shù)據(jù)庫中添加一條產(chǎn)品信息,并返回新添加的產(chǎn)品的ProductID
l UpdateProduct(productName, supplierID, categoryID, quantityPerUnit, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, productID) – 更新一個數(shù)據(jù)庫中已經(jīng)存在的產(chǎn)品,如果剛好更新了一條記錄,則返回true,否則返回false
l DeleteProduct(productID) – 刪除指定ProductID的產(chǎn)品
- using 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.ComponentModel.DataObject]
- public class ProductsBLL
- {
- private ProductsTableAdapter _productsAdapter = null;
- protected ProductsTableAdapter Adapter
- {
- get {
- if (_productsAdapter == null)
- _productsAdapter = new ProductsTableAdapter();
- return _productsAdapter;
- }
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
- public Northwind.ProductsDataTable GetProducts()
- {
- return Adapter.GetProducts();
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
- public Northwind.ProductsDataTable GetProductByProductID(int productID)
- {
- return Adapter.GetProductByProductID(productID);
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
- public Northwind.ProductsDataTable GetProductsByCategoryID(int categoryID)
- {
- return Adapter.GetProductsByCategoryID(categoryID);
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, false)]
- public Northwind.ProductsDataTable GetProductsBySupplierID(int supplierID)
- {
- return Adapter.GetProductsBySupplierID(supplierID);
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Insert, true)]
- public bool AddProduct(string productName, int? supplierID, int? categoryID, string quantityPerUnit,
- decimal? unitPrice, short? unitsInStock, short? unitsOnOrder, short? reorderLevel,
- bool discontinued)
- {
- // 新建一個ProductRow實例
- Northwind.ProductsDataTable products = 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.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 product.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;
- // 添加新產(chǎn)品
- products.AddProductsRow(product);
- int rowsAffected = Adapter.Update(products);
- // 如果剛好新增了一條記錄,則返回true,否則返回false
- return rowsAffected == 1;
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Update, true)]
- public bool UpdateProduct(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 == 0)
- // 沒有找到匹配的記錄,返回false
- return false;
- Northwind.ProductsRow product = products[0];
- product.ProductName = productName;
- if (supplierID == null) product.SetSupplierIDNull(); else product.SupplierID = supplierID.Value;
- if (categoryID == null) product.SetCategoryIDNull(); else product.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 product.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;
- // 更新產(chǎn)品記錄
- int rowsAffected = Adapter.Update(product);
- // 如果剛好更新了一條記錄,則返回true,否則返回false
- return rowsAffected == 1;
- }
- [System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Delete, true)]
- public bool DeleteProduct(int productID)
- {
- int rowsAffected = Adapter.Delete(productID);
- // 如果剛好刪除了一條記錄,則返回true,否則返回false
- return rowsAffected == 1;
- }
- }
GetProducts、GetProductByProductID、GetProductsByCategoryID以及 GetProductBySuppliersID等方法都僅僅是簡簡單單的直接調(diào)用DAL中的方法來返回數(shù)據(jù)。不過在有的情況下,我們還可能需要給它們實現(xiàn)一些業(yè)務(wù)規(guī)則(比如說授權(quán)規(guī)則,不同的用戶或不用角色應(yīng)該可以看到不同的數(shù)據(jù)),現(xiàn)在我們簡單的將它們做成這樣就可以了。那么,對于這些方法來說,BLL僅僅是作為表示層與DAL之間的代理。
AddProduct和UpdateProduct這兩個方法都使用參數(shù)中的那些產(chǎn)品信息去添加或是更新一條產(chǎn)品記錄。由于Product表中有許多字段都允許空值(CategoryID、SupplierID、UnitPrice……等等),所以AddProduct和UpdateProduct中相應(yīng)的參數(shù)就使用nullable types。Nullable types是.NET 2.0中新提供的一種用于標(biāo)明一個值類型是否可以為空的技術(shù)。在C#中,你可以在一個允許為空的值類型后面加上一個問號(比如,int? x;)。關(guān)于Nullable Types的詳細(xì)信息,你可以參考C# Programming Guide。
由于插入、修改和刪除可能不會影響任何行,所以這三種方法均返回一個bool值用于表示操作是否成功。比如說,頁面開發(fā)人員使用一個并不存在的ProductID去調(diào)用DeleteProduct,很顯然,提交給數(shù)據(jù)庫的DELETE語句將不會有任何作用,所以DeleteProduct會返回false。
注意:當(dāng)我們在添加或更新一個產(chǎn)品的詳細(xì)信息時,都是接受由產(chǎn)品信息組成的一個標(biāo)量列表,而不是直接接受一個ProductsRow實例。因為ProductsRow是繼承于ADO.NET的DataRow,而DataRow沒有默認(rèn)的無參構(gòu)造函數(shù),為了創(chuàng)建一個ProductsRow的實例,我們必須先創(chuàng)建一個ProductsDataTable的實例,然后調(diào)用它的NewProductRow方法(就像我們在AddProduct方法中所做的那樣)。不過,當(dāng)我在使用ObjectDataSource來插入或更新時,這樣做的缺點就會暴露出來了。簡單的講,ObjectDataSource會試圖為輸入的參數(shù)創(chuàng)建一個實例,如果BLL方法希望得到一個ProductsRow,那么ObjectDataSource就將會試圖去創(chuàng)建一個,不過很顯然,這樣的操作一定會失敗,因為沒有一個默認(rèn)的無參構(gòu)造函數(shù)。這個問題的詳細(xì)信息,可以在ASP.NET論壇的以下兩個帖子中找到: Updating ObjectDataSources with Strongly-Typed DataSets、Problem With ObjectDataSource and Strongly-Typed DataSet。
之后,在AddProduct和UpdateProduct中,我們創(chuàng)建了一個ProductsRow實例,并將傳入的參數(shù)賦值給它。當(dāng)給一個DataRow的DataColumns賦值時,各種字段級的有效性驗證都有可能會被觸發(fā)。因此,我們應(yīng)該手工的驗證一下傳入的參數(shù)以保證傳遞給BLL方法的數(shù)據(jù)是有效的。不幸的是,Visual Studio生成的強類型數(shù)據(jù)集(strongly-typed DataRow)并沒有使用nullable values。要表明DataRow中的一個DataColumn可以接受空值,我們就必須得使用SetColumnNameNull方法。
在UpdateProduct中,我們先使用GetProductByProductID(productID)方法將需要更新的產(chǎn)品信息讀取出來。這樣做好像沒有什么必要,不過我們將在之后的關(guān)于并發(fā)優(yōu)化(Optimistic concurrency)的課程中證明這個額外的操作是有它的作用的。并發(fā)優(yōu)化是一種保證兩個用戶同時操作一個數(shù)據(jù)而不會發(fā)生沖突的技術(shù)。獲取整條記錄同時也可以使創(chuàng)建一個僅更新DataRow的一部分列的方法更加容易,我們可以在SuppliersBLL類中找到這樣的例子。
***,注意我們在ProductsBLL類上面加上了DataObject 標(biāo)簽(就是在類聲明語句的上面的[System.ComponentModel.DataObject]),各方法上面還有DataObjectMethodAttribute 標(biāo)簽。DataObject標(biāo)簽把這個類標(biāo)記為可以綁定到一個ObjectDataSource控件,而DataObjectMethodAttribute則說明了這個方法的目的。我們將在后面的教程中看到,ASP.NET 2.0的ObjectDataSource使從一個類中訪問數(shù)據(jù)更加容易。為了ObjectDataSource向?qū)軌驅(qū)ΜF(xiàn)有的類進(jìn)行合適的篩選,在類列表中默認(rèn)僅顯示標(biāo)記為DataObject的類。當(dāng)然,其實ProductsBLL類就算沒有這個標(biāo)簽也可以工作,但是加上它可以使我們在ObjectDataSource向?qū)е械牟僮鞲虞p松和心情愉快。
添加其他的類
完成了ProductsBLL類之后,我們還要添加一些為categories、suppliers和employees服務(wù)的類。讓我們花點時間來創(chuàng)建下面的類,根據(jù)上面的例子來做就是了:
· CategoriesBLL.cs
o GetCategories()
o GetCategoryByCategoryID(categoryID)
· SuppliersBLL.cs
o GetSuppliers()
o GetSupplierBySupplierID(supplierID)
o GetSuppliersByCountry(country)
o UpdateSupplierAddress(supplierID, address, city, country)
· EmployeesBLL.cs
o GetEmployees()
o GetEmployeeByEmployeeID(employeeID)
o GetEmployeesByManager(managerID)
SuppliersBLL類中的UpdateSupplierAddress方法是一個值得注意的東西。這個方法提供了一個僅僅更新供應(yīng)商地址信息的接口。它首先根據(jù)指定的SupplierID讀出一個SupplierDataRow(使用GetSupplierBySupplierID方法),設(shè)置其關(guān)于地址的所有屬性,然后調(diào)用SupplierDataTable的Update方法。UpdateSupplierAddress方法的代碼如下所示:
- [System.ComponentModel.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)
- // 沒有找到匹配的項,返回false
- return false;
- else
- {
- Northwind.SuppliersRow supplier = suppliers[0];
- if (address == null) supplier.SetAddressNull(); else supplier.Address = address;
- if (city == null) supplier.SetCityNull(); else supplier.City = city;
- if (country == null) supplier.SetCountryNull(); else supplier.Country = country;
- // 更新供應(yīng)商的關(guān)于地址的信息
- int rowsAffected = Adapter.Update(supplier);
- // 如果剛好更新了一條記錄,則返回true,否則返回false
- return rowsAffected == 1;
- }
- }
【編輯推薦】
- 如何在IIS6.0中部署asp.net mvc程序
- 用Winform傻瓜式搭建asp.net mvc框架
- ASP.NET Session失效的編程思路
- ASP.NET Session 狀態(tài)的存儲
- 了解ASP.NET Web應(yīng)用程序模型