整個(gè)指南系列將從最簡(jiǎn)單的內容開(kāi)始,我們會(huì )首先創(chuàng )建一個(gè)數據訪(fǎng)問(wèn)層(DAL),在DAL中通過(guò)強類(lèi)型數據集(Typed DataSet)訪(fǎng)問(wèn)數據庫中的信息。
一、入門(mén)(introduction)
作為Web開(kāi)發(fā)者,我們會(huì )一直不斷的與數據打交道,比如:創(chuàng )建數據庫存儲數據;編寫(xiě)代碼訪(fǎng)問(wèn)和修改數據;通過(guò)Web頁(yè)面收集和匯總數據等等。
這個(gè)相對來(lái)說(shuō)比較長(cháng)的指南系列將會(huì )揭示asp.net2.0數據操作的通用模式。我們將從創(chuàng )建整個(gè)系列的軟件架構開(kāi)始。整個(gè)架構將包括DAL(通過(guò)強類(lèi)型數據集實(shí)現),BLL(展示業(yè)務(wù)邏輯規則)和UI(由asp.net頁(yè)面組成,而這些頁(yè)面又都共享使用一個(gè)模板來(lái)布局)。等這些基礎工作完成以后,將開(kāi)始展示數據,包括如何顯示、匯總、收集和驗證數據。
為了讓您了解的更加清楚,整個(gè)系列將會(huì )遵循簡(jiǎn)單明了和通過(guò)大量截圖分布演示的風(fēng)格來(lái)展現。每一篇文章都是用C#和VB.NET兩種語(yǔ)言編寫(xiě)代碼,你可以下載到相應語(yǔ)言的源代碼。(作者注:第一篇文章非常長(cháng),后面的就按內容分塊,相對更好理解一些)
在整個(gè)系列中,我們將會(huì )使用SQL SERVER 2005 Exdivss Edition中的示例數據庫Northwind,它會(huì )被放在項目的App_Date文件夾中,除了數據庫文件外,文件夾還包括創(chuàng )建數據庫用的SQL腳本,為您使用不同的數據庫版本提供了方便(如果你愿意的話(huà)),這些SQL腳本可以在微軟的官方網(wǎng)站下載。需要說(shuō)明的是,如果您選擇使用了一個(gè)不同的數據庫版本,需要修改Web.config文件中的NORTHWNDConnectionString的內容。整個(gè)Web應用程序通過(guò)VS2005專(zhuān)業(yè)版創(chuàng )建,項目類(lèi)型是一個(gè)基于文件系統的Web站點(diǎn)項目。當然,系列中的所有內容,都可以非常好地運行在其它免費地VS2005版本或者Visual Web Developer中。
在“入門(mén)”章節中,首先創(chuàng )建DAL,接著(zhù)第二篇文章創(chuàng )建BLL,第三篇開(kāi)始頁(yè)面布局和導航。前三篇文章將建立整個(gè)系列地基礎平臺。第一篇文章內容會(huì )稍微多一些,現在讓我們打開(kāi)VS開(kāi)始上路吧!
第1步:創(chuàng )建Web項目并連接數據庫
在我們建立DAL之前,首先創(chuàng )建一個(gè)站點(diǎn),并且安裝數據庫,下面創(chuàng )建一個(gè)新的基于文件系統的ASP.NET站點(diǎn)。操作如下:打開(kāi)VS的“文件”/“新建網(wǎng)站”菜單,顯示創(chuàng )建新網(wǎng)站對話(huà)框,選擇“asp.net web site”模板,在位置(location)下來(lái)列表中,選擇“文件系統”,選擇一個(gè)文件夾存放Web站點(diǎn),同時(shí)將語(yǔ)言改成C#.
圖1 創(chuàng )建新網(wǎng)站
上述步驟將創(chuàng )建一個(gè)新的Web站點(diǎn),包括一個(gè)Default.aspx頁(yè)面,一個(gè)App_Data文件夾和一個(gè)Web.config文件。
下一步是通過(guò)VS SERVER EXPLORER添加對數據庫的引用,通過(guò)往SERVER EXPLORE中添加數據庫,您可以添加表、存儲過(guò)程、視圖等等。您可以查看表中的數據,也可以手動(dòng)或通過(guò)QUERY BUILDER來(lái)創(chuàng )建查詢(xún),另外,我們可以指定用于創(chuàng )建強類(lèi)型數據集的數據庫。在我們提供數據庫連接字符串信息的同時(shí),VS會(huì )自動(dòng)裝載一個(gè)下拉列表用來(lái)展示已經(jīng)在SERVER EXPLORE注冊的數據庫。
添加northwind數據庫的具體步驟取決于,你是想通過(guò)App_Data文件夾中的SQL SERVER 2005 EXdivSS EDITION,還是想用SQL SERVER 2000或SQL SERVER 2005的數據庫。
1.1使用App_Data中的數據庫
如果您沒(méi)有SQL SERVER 2000或2005的數據庫服務(wù)器,或者說(shuō)您不想往數據庫服務(wù)器中添加數據庫,您可以用SQL SERVER 2005 EXdivSS EDITION版的northwind數據庫,您可以通過(guò)下載本項目的源代碼,然后在A(yíng)pp_Data中找到它(NorthWND.MDF).
位于A(yíng)pp_Data文件夾下的數據庫會(huì )自動(dòng)添加到SERVER EXPLORE中,加入您的機器已經(jīng)安裝了SQL SERVER 2005 EXdivSS EDITION,您會(huì )在SERVER EXPLORE中看到一個(gè)northwnd.mdf的節點(diǎn)。您可以展開(kāi)并查看其中的表、視圖、存儲過(guò)程等。
在A(yíng)pp_Data文件夾中,您同樣可以放置MICROSOFT ACCESS的.mdb文件,它同樣也會(huì )被自動(dòng)添加到SERVER EXPLORE中,如果您不想使用任何的SQL SERVER版本,可以下載一個(gè)MICROSOFT ACCESS版本的數據庫,并把它放在A(yíng)pp_Data中。但是注意:ACCESS數據庫相對于SQL SERVER沒(méi)有豐富的特性,而且其不是專(zhuān)為Web站點(diǎn)的開(kāi)發(fā)設計的,另外,后續的至少35篇文章中使用的特性可能ACCESS會(huì )不支持。
1.2 創(chuàng )建到SQL SERVER 2000或2005的數據庫連接
作為另一種方案,您也可以連接已經(jīng)安裝在數據庫服務(wù)器中的northwind數據庫,前提是數據庫已經(jīng)安裝到服務(wù)器了。如果沒(méi)有,您可以通過(guò)下載本示例教程中的安裝腳本或者從微軟的網(wǎng)站下載SQL SERVER 2000版的northwind和安裝腳本。
如果您已經(jīng)安裝了northwind,打開(kāi)VS中的SERVER EXPLORE,右擊“Data Connections”節點(diǎn),選擇“添加連接”。如果您沒(méi)有打開(kāi)SERVER EXPLORE,可以通過(guò)“視圖/服務(wù)器管理器”或按“ALT+CTRL+S”快捷鍵打開(kāi)。打開(kāi)“添加連接”對話(huà)框后,指定要連接的目標服務(wù)器,授權信息和數據庫,如果您已經(jīng)成功配置了數據庫連接信息,單擊“確定”按鈕,數據庫就會(huì )作為“Data Connections”節點(diǎn)下一個(gè)新節點(diǎn)添加到SERVER EXPLORE,您同樣可以展開(kāi),并查看其中的表、視圖、存儲過(guò)程等。
圖2 添加連接
第2步:創(chuàng )建DAL
處理數據的一個(gè)選擇是將處理的詳細邏輯直接放在顯示層(在Web應用程序中,ASP.NET頁(yè)面組成了顯示層),這種形式,通過(guò)將ADO.NET寫(xiě)到ASP.NET頁(yè)面下的編碼區域或者使用SQLDATASOURCE控件。這種途徑將DAL和顯示層緊密的耦合在一起。推薦的一種途徑是將DAL從顯示層分離出來(lái)。這個(gè)分離出來(lái)的層被叫做數據訪(fǎng)問(wèn)層,往往使用一個(gè)單獨的類(lèi)庫項目來(lái)實(shí)現。這種架構的優(yōu)點(diǎn)有很多,而且有許多說(shuō)明文檔。
所有數據底層數據源的代碼(如創(chuàng )建連接,進(jìn)行SELECT,INSERT,UPDATE,DELETE操作)都被放到DAL中,在顯示層不能包括任何數據訪(fǎng)問(wèn)的代碼,可以通過(guò)調用DAL來(lái)訪(fǎng)問(wèn)和請求數據。
DAL封裝了訪(fǎng)問(wèn)底層數據的典型方法,例如:northwind數據庫中有Products和Categories兩張表,分別記錄了銷(xiāo)售的商品和這些商品的類(lèi)型。在我們的DAL中,可能要創(chuàng )建如下方法:
GetCategories();返回所有類(lèi)型的信息。
GetProducts();返回所有商品的信息。
GetProductByCategoryID(CategoryID);返回特定類(lèi)型的商品。
GetProductByProductID(productid);返回某個(gè)商品的信息。
這些方法執行時(shí),會(huì )連接數據庫,實(shí)施查詢(xún),返回結果。如何返回這些結果是至關(guān)重要的。上述方法可以簡(jiǎn)單的返回一個(gè)dataset或datareader,但更完美的一種方式是:返回結果作為強類(lèi)型對象返回。所謂強類(lèi)型對象就是在編譯時(shí)就對其架構進(jìn)行了嚴格的定義,弱類(lèi)型恰恰想法,只能在運行時(shí),才被定義。
例如DataReader和默認的DataSet都是弱類(lèi)型,只能靠數據查詢(xún)返回的列來(lái)定義其架構。訪(fǎng)問(wèn)一個(gè)弱類(lèi)型的DataTable某一列的方法如下:DataTable.Rows(index)["columnName"].展示了必須通過(guò)一個(gè)字符串或下標去訪(fǎng)問(wèn)表中的一列。一個(gè)強類(lèi)型的DataTable可以將表中的每一列實(shí)現為屬性,當然,訪(fǎng)問(wèn)方式也發(fā)生了變化:DataTable.Rows(index).columnName.
為了返回一個(gè)強類(lèi)型的對象,開(kāi)發(fā)者一是可以創(chuàng )建自定義的業(yè)務(wù)對象或者可以使用強類(lèi)型的數據集。對于自定義業(yè)務(wù)對象,開(kāi)發(fā)者往往通過(guò)定義一個(gè)類(lèi)來(lái)實(shí)現,其中類(lèi)的屬性與底層數據庫相應表中的列是一一對應的。
一個(gè)強類(lèi)型的DataSet是VS根據數據庫的架構自動(dòng)產(chǎn)生的。其里面的成員都是強類(lèi)型的。強類(lèi)型數據集中包含的類(lèi)有效地擴展了ADO.NET中的DataSet,DataTable,DataRow。除了強類(lèi)型的DataTable,強類(lèi)型DataSet中還包括TableAdapter,這些類(lèi)中包含了操作DataSet中的表和將表中的改變提交到后臺數據庫的一系列的方法。
我們在整個(gè)系列中將使用強類(lèi)型數據集。下圖展示了使用強類(lèi)型數據集的應用程序層與層之間通信的工作流。
圖3 工作流
2.1 創(chuàng )建強類(lèi)型數據集和TableAdapter
下面開(kāi)始創(chuàng )建DAL,首先添加一個(gè)強類(lèi)型的數據集到項目中。步驟:右擊項目節點(diǎn),選擇“添加新項”,選擇DataSet模板,改名為northwind.xsd。
圖4 添加強類(lèi)型數據集
然后,單擊“添加”,當提示是否將DataSet添加到App_Code文件夾時(shí),選擇“是”。這是,將出現強類(lèi)型數據集設計器,同時(shí)TableAdapter配置向導將會(huì )啟動(dòng),允許您添加第一個(gè)TableAdapter到DataSet。
強類(lèi)型數據集是一個(gè)強類(lèi)型數據的集合,由多個(gè)強類(lèi)型DataTable的實(shí)例構成,每個(gè)強類(lèi)型的DataTable由多個(gè)強類(lèi)型的DataRow實(shí)例構成。我們將會(huì )為在項目中用到的底層數據庫中的每個(gè)表創(chuàng )建一個(gè)相應的強類(lèi)型DataTable。
下面是為Products表創(chuàng )建一個(gè)DataSet中的強類(lèi)型表。
請牢記,強類(lèi)型DataTables不包括訪(fǎng)問(wèn)底層數據庫表的任何信息,為了獲取數據填充這個(gè)表,我們用一個(gè)TableAdapter類(lèi)來(lái)充當DAL,對Products表而言,TableAdapter類(lèi)將包含以下方法(GetProducts(),GetProductsByCategoryId(categoryid)等)。我們可以在顯示層調用這些方法,DataTable在層與層的數據傳遞過(guò)程中充當強類(lèi)型的對象。
TableAdapter配置向導首先讓您選擇要操作的數據庫,在下拉列表中展示了SERVER EXPLORE中的所有的數據庫,如果沒(méi)有數據庫,您可以單擊“新建連接”,添加。
選擇完數據庫后,單擊下一步,您要選擇是否保存連接到Web.config文件,如果保存連接字符串,那么就不用在TableAdapter類(lèi)中硬編碼了。這樣也就避免了一旦將來(lái)連接字符串發(fā)生改變帶來(lái)的不必要的麻煩。
如果選擇保存到配置文件中,會(huì )保存在相應的<connectionstring>節,您同時(shí)可以對連接字符串進(jìn)行加密,以提供其安全性。也可以通過(guò)IIS的圖形化管理工具中的asp.net2.0的屬性頁(yè)面來(lái)修改。(這在某種程度,對管理員是一件好事)。
下一步,我們開(kāi)始定義第一個(gè)強類(lèi)型DataTable的架構,而且定義第一個(gè)方法以供TableAdapter來(lái)操作強類(lèi)型DataSet。這兩個(gè)操作,可以通過(guò)創(chuàng )建一個(gè)查詢(xún),讓其返回DataTable相應的列來(lái)實(shí)現,而且是同步實(shí)現的。在向導的最后,我們要給查詢(xún)命名一個(gè)方法名。當所有的這些都完成后,就可以通過(guò)顯示層來(lái)調用方法了。這個(gè)方法將會(huì )執行定義的查詢(xún)形成一個(gè)DataTable。
在定義查詢(xún)之前,首先要知道TableAdapter怎樣執行查詢(xún),我們可以使用單純的SQL語(yǔ)句,也可以創(chuàng )建一個(gè)新的存儲過(guò)程,或者使用一個(gè)現有的存儲過(guò)程。在我們的這個(gè)系列中,將使用單純的SQL語(yǔ)句。
那么我們就可以手工輸入SQL語(yǔ)句了,通過(guò)創(chuàng )建第一個(gè)方法,讓查詢(xún)返回相應表中的列,下圖展示了創(chuàng )建一個(gè)查詢(xún)返回Products表中所有的行和列。
當然,也可以使用查詢(xún)生成器,可視化創(chuàng )建查詢(xún)。
創(chuàng )建完查詢(xún)后,在轉到下一頁(yè)面前,單擊“高級”按鈕,在WEB SITE項目中,“Generate Insert,update,and delete statement”是唯一的默認選中項;如果您的項目是類(lèi)庫或者是Windows項目,“use optimistic concurrency”選項也是被選中的,現在請不要選擇這個(gè)復選框,對于這一話(huà)題,將在以后的文章中探討。
配置完高級選項后,單擊“下一步”到最后一個(gè)頁(yè)面,我們將選擇哪個(gè)方法添加到TableAdapter中,有兩種方式:
填充一個(gè)表:創(chuàng )建一個(gè)方法,以查詢(xún)結果生成的DataTable作為參數,并對其進(jìn)行處理。例如:ADO.NET TableAdapter類(lèi)調用Fill()方法。
返回一個(gè)表:方法用來(lái)創(chuàng )建、填充表,表作為方法的返回值。
您可以讓TableAdapter實(shí)現其中一個(gè)或兩個(gè)方法都實(shí)現,您也可以給方法改名。這里我們兩個(gè)選項全選,但后續的文章中將使用后一種方法。同時(shí)將通用的GetData方法名改為GetProducts()。
如果選中了最后一個(gè)checkbox,“GenerateDbDirectMethod”將會(huì )為T(mén)ableAdapter創(chuàng )建Insert,Update和Delete方法。
如果不選,所有的更新將通過(guò)TableAdapter唯一的方法Update來(lái)實(shí)施。而唯一的這個(gè)方法,對強類(lèi)型的Dataset,DataTable,DataRow或者行組都是通用的。
單擊“完成”完成向導,這時(shí)我們在設計器中得到一張表??梢钥吹奖碇械乃械牧?,(ProductId,ProductName等),同時(shí)還有ProductTableAdapter的所有方法(Fill方法和GetProducts方法)。
至此為止,我們創(chuàng )建了一個(gè)強類(lèi)型數據集和一個(gè)表,和一個(gè)強類(lèi)型的DataAdapter類(lèi)。這些對象可以用來(lái)訪(fǎng)問(wèn)商品列表,代碼如下:
NorthwindTableAdapters.ProductsTableAdapter productsAdapter =
new NorthwindTableAdapters.ProductsTableAdapter();
Northwind.ProductsDataTable products;
products = productsAdapter.GetProducts();
foreach (Northwind.ProductsRow productRow in products)
Response.Write("Product: " + productRow.ProductName + "<br />");
我們不需要寫(xiě)任何代碼,也不需要實(shí)例化任何ADO.NET類(lèi),不需要去管連接字符串,SQL查詢(xún)和存儲過(guò)程。TableAdapter會(huì )為我們自動(dòng)生成這些底層的代碼。
本例中的每一個(gè)對象都是強類(lèi)型的,允許VS提供智能感知和編譯時(shí)的類(lèi)型判斷。大多數的TableAdapter返回的表都可以綁定到Web數據控件(GridView等)。下面的代碼演示了如何將GetProducts方法返回的結果綁定到一個(gè)GridView。
AllProducts.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="AllProducts.aspx.cs"
Inherits="AllProducts" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"