• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            道。道。道

            安全特性不等于安全的特性

               :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理

            常用鏈接

            搜索

            •  

            最新評(píng)論

            導(dǎo)言

              作為web開(kāi)發(fā)人員,我們的生活圍繞著數(shù)據(jù)操作。我們建立數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)數(shù)據(jù),寫(xiě)編碼來(lái)訪問(wèn)和修改數(shù)據(jù),設(shè)計(jì)網(wǎng)頁(yè)來(lái)采集和匯總數(shù)據(jù)。本文是研究在ASP.NET 2.0中實(shí)現(xiàn)這些常見(jiàn)的數(shù)據(jù)訪問(wèn)模式之技術(shù)的長(zhǎng)篇系列教程的第一篇。我們將從創(chuàng)建一個(gè)軟件框架開(kāi)始,這個(gè)框架的組成部分包括一個(gè)使用強(qiáng)類(lèi)型的DataSet的數(shù)據(jù)訪問(wèn)層(DAL),一個(gè)實(shí)施用戶(hù)定義的業(yè)務(wù)規(guī)則的業(yè)務(wù)邏輯層(BLL),以及一個(gè)由共享頁(yè)面布局的ASP.NET網(wǎng)頁(yè)組成的表現(xiàn)層。在打下這個(gè)后端的基礎(chǔ)工作之后,我們將開(kāi)始轉(zhuǎn)向報(bào)表,示范如何顯示,匯總,采集,和驗(yàn)證web 應(yīng)用的數(shù)據(jù)。這些教程旨在簡(jiǎn)明扼要,使用了許多屏幕截圖,提供了按步就 班(step-by-step)的指導(dǎo),帶你經(jīng)歷這個(gè)開(kāi)發(fā)過(guò)程。每個(gè)教程都有C# 版和VB版,并且附有涉及的完整的編碼的下載。(這第一個(gè)教程比較長(zhǎng),但以后其他的教程將以更容易消化的篇幅推出。)

              在這些教程中,我們將使用置于App_Data 目錄內(nèi)的微 軟SQL Server 2005 Express版的Northwind數(shù)據(jù)庫(kù)。除了數(shù)據(jù)庫(kù)文件外,App_Data目錄還帶有用于創(chuàng)建數(shù)據(jù)庫(kù)的SQL腳本,萬(wàn)一你想使用別的數(shù)據(jù)庫(kù)版本的話。如果你愿意的話,你也可以直接從微軟下載這些腳本。如果你使用別的SQL Server版本的Northwind數(shù)據(jù)庫(kù)的話,你需要更新Web.config文件中的NORTHWNDConnectionString設(shè)置。本教程中的web應(yīng)用是個(gè)基于文件系統(tǒng)的網(wǎng)站項(xiàng)目,是使用Visual Studio 2005 專(zhuān)業(yè)版建立起來(lái)的。但是,所有的教程都可以在Visual Studio 2005的免費(fèi)版本Visual Web Developer中運(yùn)行。

              在這個(gè)教程里,我們將從頭開(kāi)始,先創(chuàng)建一個(gè)數(shù)據(jù)訪問(wèn)層(DAL),然后在第二個(gè)教程里創(chuàng)建一個(gè)業(yè)務(wù)邏輯層(BLL),在第三個(gè)教程里設(shè)計(jì)頁(yè)面布局和導(dǎo)航。以后的教程將建立在這三個(gè)教程的基礎(chǔ)之上。在第一個(gè)教程里,我們要討論的內(nèi)容多多,所以,請(qǐng)打開(kāi)Visual Studio,讓我們動(dòng)起手來(lái)!

              第一步:創(chuàng)建一個(gè)Web項(xiàng)目,配置數(shù)據(jù)庫(kù)連接

              在我們開(kāi)始創(chuàng)建數(shù)據(jù)訪問(wèn)層(DAL)之前,我們首先需要?jiǎng)?chuàng)建一個(gè)網(wǎng)站,以及建立一個(gè)數(shù)據(jù)庫(kù)。我們從創(chuàng)建一個(gè)基于文件系統(tǒng)的ASP.NET 網(wǎng)站開(kāi)始。次序如下,打開(kāi)文件(File)菜單,選擇新的網(wǎng)站 (New Web Site),系統(tǒng)會(huì)顯示一個(gè)新網(wǎng)站對(duì)話框,選擇ASP.NET網(wǎng)站模板(Web Site template),設(shè)置定 位(Location)列表的選項(xiàng)為文件系統(tǒng)( File System),然后選這一個(gè)放置這個(gè)網(wǎng)站的文件夾,然后選擇編程語(yǔ) 言為C#。


            圖 1: 創(chuàng)建一個(gè)基于文件系統(tǒng)的網(wǎng)站

              Visual Studio會(huì)為你生成一個(gè)新的網(wǎng)站,同時(shí)生成一個(gè)名為Default.aspx的網(wǎng)頁(yè),和一 個(gè)App_Data文件夾。

              網(wǎng)站生成之后,下一步是在Visual Studio的服務(wù)器資源管理器(Server Explorer)里為你的數(shù)據(jù)庫(kù)添加一個(gè)引 用(reference)。把一個(gè)數(shù)據(jù)庫(kù)添加到服務(wù)器資源管理器之后,你就能在Visual Studio環(huán)境里添加數(shù)據(jù)表,存 儲(chǔ)過(guò)程,視圖等等。你也能查看數(shù)據(jù)庫(kù)里的數(shù)據(jù),手工或用查詢(xún)生成器(Query Builder)的圖形界面建立你自己的查詢(xún)語(yǔ)句。此外,當(dāng)我們?yōu)镈AL創(chuàng)建強(qiáng)類(lèi)型的DataSet時(shí),我們需要把Visual Studio指向作為DataSet數(shù)據(jù)源的目標(biāo)數(shù)據(jù)庫(kù)。雖然我們可以在適當(dāng)時(shí)候提供所昀敳獴搨 ???oЁ涉及的數(shù)據(jù)庫(kù)連接信息,但假如我們預(yù) 先在服務(wù)器資源管理器里注冊(cè)這些數(shù)據(jù)庫(kù)的話,Visual Studio會(huì)自動(dòng)把這些數(shù)據(jù)庫(kù)填充到一個(gè)下拉列表中去 。

              把Northwind數(shù)據(jù)庫(kù)添加到服務(wù)器資源管理器中去的步驟取決于你想使用放置在App_Data文件夾 里的SQL Server 2005 Express 版本數(shù)據(jù)庫(kù),還是你想使用已經(jīng)建立好了的SQL Server 2000或2005 數(shù)據(jù)庫(kù)服 務(wù)器。

              使用置于App_Data文件夾中的數(shù)據(jù)庫(kù)

              如果你沒(méi)有可連接的SQL Server 2000 或2005服務(wù)器,或者你就是想避免給數(shù)據(jù)庫(kù)服務(wù)器添加數(shù)據(jù)庫(kù),你可以使用SQL Server 2005 Express版的Northwind數(shù)據(jù)庫(kù),該數(shù)據(jù)庫(kù)位于下載源碼中的App_Data文件夾里(NORTHWND.MDF)。

              置于App_Data文件夾里的數(shù)據(jù)庫(kù)會(huì)被自動(dòng)添加到服務(wù)器資源管理器中。假設(shè)你已經(jīng)在你的機(jī)器上安裝了SQL Server 2005 Express版本,那么你應(yīng)該在服務(wù)器資源管理器中看到一個(gè)名為NORTHWND.MDF的節(jié)點(diǎn),你可以將這個(gè)節(jié)點(diǎn)擴(kuò)展開(kāi)來(lái),瀏覽其中的數(shù)據(jù)表,視圖,存儲(chǔ)過(guò)程等等 (參考圖2)。

              App_Data文件夾還可以放置微軟的Access.mdb數(shù)據(jù)庫(kù)文件,跟SQL Server 的數(shù) 據(jù)庫(kù)文件類(lèi)似,這些Access文件會(huì)被自動(dòng)地添加到服務(wù)器資源管理器中。如果你不想用任何SQL Server數(shù)據(jù)庫(kù),那么你總歸可以下載微軟Access版本的Northwind 數(shù)據(jù)庫(kù)文件,然后將其放置于App_Data文件夾中。但記住,Access數(shù)據(jù)庫(kù)沒(méi)有SQL Server那么多功能,而且它并不是設(shè)計(jì)來(lái)在網(wǎng)站情形下使用的。此外,在后面幾個(gè)教程里將用到Access數(shù)據(jù)庫(kù)不支持的數(shù)據(jù)庫(kù)層次的功能。

              連接到微軟SQL Server 2000或2005數(shù)據(jù)庫(kù)服務(wù)器中的數(shù)據(jù)庫(kù)

              或者,你也可以連接到安裝在數(shù)據(jù)庫(kù)服務(wù)器上的Northwind數(shù)據(jù)庫(kù)。假如數(shù)據(jù)庫(kù)服務(wù)器上尚未安裝Northwind數(shù)據(jù)庫(kù)的話,你首先必須運(yùn)行本教程下載文件中的安裝腳本來(lái)把數(shù)據(jù)庫(kù)添加到數(shù)據(jù)庫(kù)服務(wù)器上去,或者你也可以從微軟網(wǎng)站上直接下載SQL Server 2000的Northwind數(shù)據(jù)庫(kù)以及安裝腳本

              安裝數(shù)據(jù)庫(kù)完畢之后,去Visual Studio中的服務(wù)器資源管理器,在數(shù)據(jù)連接(Data Connections)節(jié)點(diǎn)上按右鼠標(biāo),選擇“添加連接(Add Connection)”。如果你看不到服務(wù)器資源管理器,去菜單“查看(View)”點(diǎn)擊 “服務(wù)器資源管理器”,或者按組合鍵Ctrl+Alt+S來(lái)打開(kāi)服務(wù)器資源管理器。這會(huì)打開(kāi)添加連接的對(duì)話框,在這上面,你可以設(shè)置需要連接的服務(wù)器,認(rèn)證信息,以及數(shù)據(jù)庫(kù)名字。在你成功配置數(shù)據(jù)庫(kù)連接信息,按OK按鈕之后,數(shù)據(jù)庫(kù)就會(huì)被添加成數(shù)據(jù)連接節(jié)點(diǎn)之下的一個(gè)節(jié)點(diǎn)。然后,你就可以擴(kuò)展數(shù)據(jù)庫(kù)節(jié)點(diǎn)來(lái)瀏覽數(shù)據(jù)表,視圖,存儲(chǔ)過(guò)程等等。


            圖 2: 添加一個(gè)到你的數(shù)據(jù)庫(kù)服務(wù)器上的Northwind數(shù)據(jù)庫(kù)的連接

              第二步:創(chuàng)建一個(gè)數(shù)據(jù)訪問(wèn)層

              與數(shù)據(jù)打交道時(shí),一種做法是把跟數(shù)據(jù)相關(guān)的邏輯直接放在表現(xiàn)層中(在一個(gè)web應(yīng)用里,ASP.NET網(wǎng)頁(yè)構(gòu)成了表現(xiàn)層)。其形式一般是在ASP.NET 網(wǎng)頁(yè)的編碼部分寫(xiě)ADO.NET 編碼或者在標(biāo)識(shí)符部 分使用SqlDataSource控件。在這兩種形式里,這種做法都把數(shù)據(jù)訪問(wèn)邏輯與表現(xiàn)層緊密耦合起來(lái)了。但推薦 的做法是,把數(shù)據(jù)訪問(wèn)邏輯從表現(xiàn)層分離開(kāi)來(lái)。這個(gè)分開(kāi)的層被稱(chēng)作是數(shù)據(jù)訪問(wèn)層,簡(jiǎn)寫(xiě)為DAL,一般是通過(guò) 一個(gè)單獨(dú)的類(lèi)庫(kù)項(xiàng)目來(lái)實(shí)現(xiàn)的。這種分層框架的好處在很多文獻(xiàn)里都有闡述(詳見(jiàn)本教程最后的“附加讀物”里 的資源),在本系列中我們將采用這種方法。

              跟底層數(shù)據(jù)源相關(guān)的所有編碼,譬如建立到數(shù)據(jù)庫(kù)的連接,發(fā)出SELECT,INSERT ,UPDATE,和DELETE命令等的編碼,都應(yīng)該放置在DAL中。表現(xiàn)層不應(yīng)該包含對(duì) 這些數(shù)據(jù)訪問(wèn)編碼的任何引用,而應(yīng)該調(diào)用DAL中的編碼來(lái)作所有的數(shù)據(jù)訪問(wèn)請(qǐng)求。數(shù)據(jù)訪問(wèn)層包含訪問(wèn)底層數(shù)據(jù)庫(kù)數(shù)據(jù)的方法。譬如,Northwind數(shù)據(jù)庫(kù)中,有Products和Categories兩個(gè)表,它們記錄了可供銷(xiāo)售的產(chǎn)品以及這些產(chǎn)品 所屬的分類(lèi)。在我們的DAL中,我們將有下面這樣的方法:
            • GetCategories(), 返回所有分類(lèi)的信息
            • GetProducts(), 返回所有產(chǎn)品的信息
            • GetProductsByCategoryID(categoryID), 返回屬于指定分類(lèi)的所有產(chǎn)品的信 息
            • GetProductByProductID(productID), 返回指定產(chǎn)品的信息
              這些方法,被調(diào)用后,將連接到數(shù)據(jù)庫(kù),發(fā)出合適的查詢(xún),然后返回結(jié)果。我們?nèi)绾畏祷剡@些結(jié)果是很重要的 。這些方法可以直接返回?cái)?shù)據(jù)庫(kù)查詢(xún)填充的DataSet 或者DataReader ,但理想的辦法是把這些結(jié)果以強(qiáng)類(lèi) 型對(duì)象的形式返回。一個(gè)強(qiáng)類(lèi)型的對(duì)象,其schema是編譯時(shí)嚴(yán)格定義好的,而相比之下,弱類(lèi)型的對(duì)象, 其schema在運(yùn)行時(shí)之前是未知的。

              譬如,DataReader和普通的DataSet是弱類(lèi)型對(duì)象,因?yàn)樗鼈兊膕chema是被用來(lái)填充它們的數(shù)據(jù)庫(kù)查詢(xún)返回的字段來(lái)定義的。要訪問(wèn)弱類(lèi)型DataTable中的一個(gè)特定字段,我們需要用這樣的句法:DataTable.Rows[index] ["columnName"]。這個(gè)例子中的DataTable的弱類(lèi)型性質(zhì)表現(xiàn)在于,我們需要通過(guò)一個(gè)字符串或序號(hào)索引來(lái)訪問(wèn)字段名稱(chēng)。而在另一個(gè)方面,一個(gè)強(qiáng)類(lèi)型的DataTable,它的所有的字段都是通過(guò)屬性的形式來(lái)實(shí)現(xiàn)的 ,訪問(wèn)的編碼就會(huì)象這樣:DataTable.Rows[index].columnName

              要返回強(qiáng)類(lèi)型對(duì)象,開(kāi)發(fā)人員可以創(chuàng)建自定義業(yè)務(wù)對(duì)象,或者使用強(qiáng)類(lèi)型的DataSet。開(kāi)發(fā)人員實(shí)現(xiàn)的業(yè)務(wù)對(duì) 象類(lèi),其屬性往往是對(duì)相應(yīng)的底層數(shù)據(jù)表的字段的映射。而一個(gè)強(qiáng)類(lèi)型的DataSet,則是Visual Studio基于數(shù) 據(jù)庫(kù)schema為你生成的一個(gè)類(lèi),其成員的類(lèi)型都是由這個(gè)schema決定的。強(qiáng)類(lèi)型的DataSet本身,是由繼承 于ADO.NET中DataSet,DataTable,和DataRow類(lèi)的子類(lèi)組成的。除了強(qiáng)類(lèi)型的DataTable外,強(qiáng)類(lèi)型的DataSet現(xiàn)在還包括TableAdapter類(lèi),這些類(lèi)包含了填充DataSet中的DataTable和把 DataTable的改動(dòng)傳回?cái)?shù)據(jù)庫(kù)的各種方法。

              在這些教程的架構(gòu)里,我們將使用強(qiáng)類(lèi)型的DataSet。圖3示范說(shuō)明了使用強(qiáng)類(lèi)型的DataSet之應(yīng)用程序的不 同層間的流程(workflow)。


            圖 3: 把所有的數(shù)據(jù)訪問(wèn)編碼委托給DAL

              創(chuàng)建強(qiáng)類(lèi)型的DataSet和Table Adapter

              我們開(kāi)始創(chuàng)建我們的DAL,先給我們的項(xiàng)目添加一個(gè)強(qiáng)類(lèi)型的DataSet。做法如下,在昀敳獴搨 ???oЁ解決方案管理器里的項(xiàng)目 節(jié)點(diǎn)上按右鼠標(biāo),選擇“添加新項(xiàng)(Add a New Item)”。在模板列單里選擇DataSet,將其命名 為Northwind.xsd。


            圖 4: 給你的項(xiàng)目添加一個(gè)新的DataSet

              在點(diǎn)擊“添加(Add)”按鈕后,Visual Studio會(huì)問(wèn)我們是否將DataSet添加到App_Code文件夾中,選擇“Yes” 。然后Visual Studio會(huì)顯示強(qiáng)類(lèi)型的DataSet的設(shè)計(jì)器,同時(shí)會(huì)啟動(dòng)TableAdapter配置向?qū)В试S你給你的強(qiáng) 類(lèi)型DataSet添加第一個(gè)TableAdapter。

              強(qiáng)類(lèi)型的DataSet 起了強(qiáng)類(lèi)型對(duì)象的集合的作用,它由強(qiáng)類(lèi)型DataTable實(shí)例組成,每個(gè)強(qiáng)類(lèi)型DataTable又進(jìn) 而由強(qiáng)類(lèi)型的DataRow實(shí)例組成。我們將為這個(gè)教程系列要用到的每個(gè)數(shù)據(jù)表建立一個(gè)對(duì)應(yīng)的強(qiáng)類(lèi)型DataTable 。讓我們開(kāi)始吧,先為Products表建立一個(gè)DataTable。

              記住,強(qiáng)類(lèi)型的DataTable并不包括如何訪問(wèn)對(duì)應(yīng)底層的數(shù)據(jù)表的任何信息。要獲取用來(lái)填充DataTable的數(shù)據(jù) ,我們使用TableAdapter類(lèi),它提供了數(shù)據(jù)訪問(wèn)層的功能。對(duì)于我們的Products DataTable, 相應(yīng)的TableAdapter 類(lèi)將包 括GetProducts()和GetProductByCategoryID(categoryID)等方法,而我 們將在表現(xiàn)層調(diào)用這些方法。DataTable的作用是在分層間傳輸數(shù)據(jù)。

              TableAdapter配置向?qū)紫纫氵x擇使用哪個(gè)數(shù)據(jù)庫(kù)。下拉框里列出了服務(wù)器資源管理器內(nèi)的那些數(shù)據(jù)庫(kù)。如 果你預(yù)先沒(méi)有把Northwind數(shù)據(jù)庫(kù)添加到服務(wù)器資源管理器里去的話,這時(shí)你可以點(diǎn)擊新連接按鈕來(lái)添加。


            圖 5: 在下拉框里選擇Northwind數(shù)據(jù)庫(kù)

              選擇好數(shù)據(jù)庫(kù)后,按“下一步”按鈕,向?qū)?huì)問(wèn)你是否想在Web.config文件里存放連接字符串。 將連接字符串存放在Web.config文件里,你可以避免把連接字符串硬寫(xiě)在TableAdapter類(lèi)的編 碼中,如果將來(lái)連接字符串信息改動(dòng)的話,這種做法會(huì)極大地簡(jiǎn)化要做的編碼改動(dòng)。如果你選擇在配置文件存 放連接字符串,連接字符串將被置放于<connectionStrings>段落中,這個(gè)段落可以被加密來(lái)提高安全,也可以通過(guò)IIS 圖形界面管理工具中的新的ASP.NET 2.0屬性頁(yè)來(lái)修改。當(dāng)然這個(gè)工具更適于管理員。


            圖6: 在Web.config中存放連接字符串

              接下來(lái),我們需要定義第一個(gè)強(qiáng)類(lèi)型的DataTable的schema,同時(shí)為用來(lái)填充強(qiáng)類(lèi)型DataSet的TableAdapter類(lèi) 提供第一個(gè)方法。這兩步可以通過(guò)建立一個(gè)返回對(duì)應(yīng)于DataTable的數(shù)據(jù)表的字段的查詢(xún)同時(shí)完成。在向?qū)У?最后,我們將為這個(gè)查詢(xún)對(duì)應(yīng)的方法命名。完成后,這個(gè)方法可以在表現(xiàn)層調(diào)用,它會(huì)執(zhí)行設(shè)置好的查詢(xún),進(jìn) 而填充一個(gè)強(qiáng)類(lèi)型的DataTable。

              開(kāi)始定義SQL查詢(xún)之前,我們必須首先選擇我們想要TableAdapter執(zhí)行查詢(xún)的方式。我們可以直接用ad-hoc的SQL語(yǔ)句,或建立一個(gè)新的存儲(chǔ)過(guò)程,或使用現(xiàn)存的存儲(chǔ)過(guò)程。在這些教程里,我們將使用ad-hoc的SQL語(yǔ)句。


            圖 7: 用SQL語(yǔ)句查詢(xún)數(shù)據(jù)

              至此,我們可以手工輸入SQL查詢(xún)。當(dāng)生成TableAdapter的第一個(gè)方法時(shí),你一般想要讓你的查詢(xún)返回那些需 要在對(duì)應(yīng)的DataTable中存放的字段。我們可以建立一個(gè)從Products表里返回所有字段,所有數(shù) 據(jù)行的查詢(xún)來(lái)達(dá)到我們的目的:


            圖 8: 在文本框里輸入SQL查詢(xún)

              或者,我們可以使用查詢(xún)生成器(Query Builder),用圖形界面來(lái)構(gòu)造查詢(xún),如圖9所示。


            圖 9: 通過(guò)查詢(xún)編輯器生成查詢(xún)

              在生成查詢(xún)之后,在移到下一屏之前,點(diǎn)擊“高級(jí)選項(xiàng)(Advanced Options)”按鈕。在網(wǎng)站項(xiàng)目里,在默認(rèn) 情形下,“生成插入,更新,刪除語(yǔ)句”是唯一已被選中的選項(xiàng)。如果你在類(lèi)庫(kù)項(xiàng)目或Windows項(xiàng)目里運(yùn)行這個(gè) 向?qū)У脑挘?#8220;采用優(yōu)化的并發(fā)控制(optimistic concurrency)”選項(xiàng)也會(huì)被選中。現(xiàn)在先別選“采用優(yōu)化的并發(fā) 控制”這個(gè)選項(xiàng)。在以后的教程里我們會(huì)詳細(xì)討論優(yōu)化的并發(fā)控制。


            圖 10: 只選“生成插入,更新和刪除語(yǔ)句”這個(gè)選項(xiàng)

              在核實(shí)高級(jí)選項(xiàng)后,按“下一步(Next)”按鈕轉(zhuǎn)到最后一屏。在這里,配置向?qū)?huì)問(wèn)我們要給TableAdapter選擇添加什么方法。填充數(shù)據(jù)有兩種模式:
            • 填充DataTable – 這個(gè)做法會(huì)生成一個(gè)方法,該方法接受一個(gè)DataTable的參數(shù),基于查詢(xún)的結(jié)果 填充這個(gè)DataTable。譬如,ADO.NET的DataAdapter類(lèi)就是在它的Fill()方法中實(shí)現(xiàn)這個(gè)模式的 。
            • 返回DataTable – 這個(gè)做法會(huì)生成一個(gè)方法,該方法會(huì)創(chuàng)建并填充一個(gè)DataTable,然后將 其作為方法的返回值。

              你可以讓TableAdapter實(shí)現(xiàn)其中一個(gè)模式或者同時(shí)實(shí)現(xiàn)兩個(gè)模式。你也可以重新命名這里提供的這些方法。讓 我們對(duì)兩個(gè)復(fù)選框的選項(xiàng)不做改動(dòng),雖然我們?cè)谶@些教程里只需要使用后面這個(gè)模式。同時(shí),讓我們把那個(gè)很 一般性的GetData方法名改成GetProducts。

              這最后一個(gè)復(fù)選框,“生成DB直接方法(GenerateDBDirectMethods)”,如果選了的話,會(huì)為T(mén)ableAdapter自動(dòng)生 成Insert(),Update(),和Delete()方法。如果你不選這個(gè)選項(xiàng) 的話,所有的更新都需要通過(guò)TableAdapter唯一的Update()方法來(lái)實(shí)現(xiàn),該方法接受一個(gè)強(qiáng)類(lèi)型的DataSet,或者一個(gè)DataTable,或者單個(gè)DataRow,或者一個(gè)DataRow數(shù)組。(假如你 在圖9所示的高級(jí)屬性里把“生成添加,更新和刪除語(yǔ)句”的選項(xiàng)去掉的話,這個(gè)復(fù)選框是不起作用的)。讓我們 保留這個(gè)復(fù)選框的選項(xiàng)。


            圖 11: 把方法名字從 GetData 改成 GetProducts

              按“完成”按鈕結(jié)束向?qū)АT谙驅(qū)шP(guān)閉后,我們回到DataSet設(shè)計(jì)器中,它會(huì)顯示我們剛創(chuàng)建的DataTable。你可 以看到Products DataTable的字段列單(ProductID, ProductName 等),還有ProductsTableAdapter的Fill()和GetProducts()方法 。


            圖 12: Products DataTable和ProductsTableAdapter被添加到強(qiáng)類(lèi) 型DataSet中

              至此,我們生成了含有單一DataTable類(lèi)(Northwind.Products)的強(qiáng)類(lèi)型DataSet以及一個(gè)含 有GetProducts()方法的強(qiáng)類(lèi) 型DataAdapter類(lèi)(NorthwindTableAdapters.ProductsTableAdapter)。通過(guò)這些對(duì)象可以用下 列編碼來(lái)獲取所有產(chǎn)品的列單:

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        
            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ù)據(jù)訪問(wèn)有關(guān)的編碼。我們不需要生成任何ADO.NET類(lèi)的實(shí)例,我們不需要 指明任何連接字符串,任何SQL查詢(xún)語(yǔ)句,或者任何存儲(chǔ)過(guò)程。TableAdapter為我們提供了底層的數(shù)據(jù)訪問(wèn)編 碼!

              這個(gè)例子里的每個(gè)對(duì)象都是強(qiáng)類(lèi)型的,允許Visual Studio提供IntelliSense幫助以及編譯時(shí)類(lèi)型檢查。最棒 的是,從TableAdapter 返回的DataTable可以直接綁定到ASP.NET數(shù)據(jù)Web 控件上去,這樣的控件包 括GridView,DetailsView,DropDownList,CheckBoxList,以及另外幾個(gè)控件。下面這個(gè)例子示范只要 在Page_Load事件處理函數(shù)里添加短短的三行編碼就能將從GetProducts()方法返 回的DataTable綁定到一個(gè)GridView上去。

              AllProducts.aspx

            ASP.NET
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        25
                        26
                        
            <%@ Page Language="C#"
                        AutoEventWireup="true" CodeFile="AllProducts.aspx.cs"
                        Inherits="AllProducts" %>
                        <!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>View All Products in a GridView</title>
                        <link href="Styles.css"
                        rel="stylesheet"
                        type="text/css"
                        />
                        </head>
                        <body>
                        <form id="form1" runat="server">
                        <div>
                        <h1>
                        All Products</h1>
                        <p>
                        <asp:GridView ID="GridView1" runat="server"
                        CssClass="DataWebControlStyle">
                        <HeaderStyle CssClass="HeaderStyle" />
                        <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                        </asp:GridView>
                        &nbsp;</p>
                        </div>
                        </form>
                        </body>
                        </html>
                        

              AllProducts.aspx.cs

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        
            using System;
                        using System.Data;
                        using System.Configuration;
                        using System.Collections;
                        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;
                        public partial class
                        AllProducts : System.Web.UI.Page
                        {
                        protected void
                        Page_Load(object sender, EventArgs e)
                        {
                        ProductsTableAdapter productsAdapter = new
                        ProductsTableAdapter();
                        GridView1.DataSource = productsAdapter.GetProducts();
                        GridView1.DataBind();
                        }
                        }
                        


            圖 13: 顯示在GridView里的產(chǎn)品列單

              這個(gè)例子要求我們?cè)贏SP.NET網(wǎng)頁(yè)的Page_Load事件處理函數(shù)里,寫(xiě)三行編碼。在以后的教程里,我們將討 論使用ObjectDataSource,用聲明的方式來(lái)從DAL中獲取數(shù)據(jù)。用ObjectDataSource的話,我們一行編碼都不 用寫(xiě),而且還能得到分頁(yè)和排序支持呢!

              第三步:給數(shù)據(jù)訪問(wèn)層添加參數(shù)化的方法

              至此,ProductsTableAdapter只有一個(gè)方法,GetProducts(),它返回?cái)?shù)據(jù)庫(kù)里的所有產(chǎn)品。能夠操作所有的產(chǎn)品當(dāng)然有用,但很多時(shí)候我們想要獲取關(guān)于一個(gè)指定產(chǎn)品的信息,或者屬于某個(gè)特 定分類(lèi)的所有產(chǎn)品。要想給我們的數(shù)據(jù)訪問(wèn)層添加這樣的功能,我們可以給TableAdapter添加參數(shù)化的方法。

              讓我們來(lái)添加一個(gè)GetProductsByCategoryID(categoryID)方法。為給DAL添加新的 方法,讓我們回到DataSet設(shè)計(jì)器,在ProductsTableAdapter上按右鼠標(biāo),然后選擇“添加查 詢(xún)(Add Query)”。


            圖 14: 在TableAdapter上按右鼠標(biāo),選擇“添加查詢(xún)”

              向?qū)紫葧?huì)問(wèn)我們是否要通過(guò)一個(gè)ad-hoc SQL語(yǔ)句還是生成一個(gè)新存儲(chǔ)過(guò)程或者使用現(xiàn)有存儲(chǔ)過(guò)程來(lái)訪問(wèn) 數(shù)據(jù)庫(kù)。讓我們還是選擇使用SQL 語(yǔ)句。接著,向?qū)?huì)問(wèn)我們使用什么類(lèi)型的SQL查詢(xún)。因?yàn)槲覀兿敕祷貙儆?指定分類(lèi)的所有產(chǎn)品,我們需要寫(xiě)一個(gè)返回?cái)?shù)據(jù)行的SELECT語(yǔ)句。


            圖 15: 選擇生成一個(gè)返回?cái)?shù)據(jù)行的SELECT語(yǔ)句

              下一步是定義用于訪問(wèn)數(shù)據(jù)的SQL查詢(xún)語(yǔ)句。因?yàn)槲覀冎幌敕祷貙儆谥付ǚ诸?lèi)的那些產(chǎn)品,我重 用GetProducts()里的SELECT語(yǔ)句,但添加了一個(gè)WHERE 子 句:WHERE CategoryID = @CategoryID。其中的@CategoryID參數(shù) 向TableAdapter配置向?qū)П硎疚覀冋谏傻姆椒▽⑿枰粋€(gè)對(duì)應(yīng)類(lèi)(即,可為null-nullable的整數(shù))的輸入 參數(shù)。


            圖 16: 輸入一個(gè)只返回指定分類(lèi)的產(chǎn)品的查詢(xún)

              在最后一步,我們可以選擇使用何種數(shù)據(jù)訪問(wèn)模式,還可以定制生成的方法的名字。對(duì)應(yīng)于Fill 模式,讓我們把名字改成FillByCategoryID,對(duì)返回DataTable模式的方法(GetX方法),讓我們來(lái)用GetProductsByCategoryID這個(gè)名字。


            圖 17: 為T(mén)ableAdapter的方法選擇名字

              在結(jié)束向?qū)Ш螅珼ataSet設(shè)計(jì)器包含了這些新的TableAdapter的方法。


            圖18: 通過(guò)分類(lèi)來(lái)查詢(xún)產(chǎn)品

              花點(diǎn)時(shí)間用同樣的手法添加一個(gè)GetProductByProductID(productID) 方法。

              這些參數(shù)化的查詢(xún)可以在DataSet設(shè)計(jì)器里直接測(cè)試。在TableAdapter中的方法上按右鼠標(biāo),然后選擇“預(yù) 覽數(shù)據(jù)(Preview Data)”。接著,輸入對(duì)應(yīng)參數(shù)的值,然后按“預(yù)覽(Preview)”。


            圖19: 屬于飲料(Beverages)類(lèi)的那些產(chǎn)品列單

              通過(guò)我們的DAL中的GetProductsByCategoryID(categoryID)方法,我們就能設(shè)計(jì)一 個(gè)ASP.NET網(wǎng)頁(yè)來(lái)顯示屬于指定分類(lèi)的那些產(chǎn)品。下面這個(gè)例子顯示了屬于Beverages(飲 料)類(lèi)(CategoryID=1)的所有產(chǎn)品。

              Beverages.aspx

            ASP.NET
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        
            <%@ Page Language="C#"
                        AutoEventWireup="true" CodeFile="Beverages.aspx.cs"
                        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>
                        &nbsp;</p>
                        </div>
                        </form>
                        </body>
                        </html>
                        

              Beverages.aspx.cs

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        
            using System;
                        using System.Data;
                        using System.Configuration;
                        using System.Collections;
                        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;
                        public partial class
                        Beverages : System.Web.UI.Page
                        {
                        protected void
                        Page_Load(object sender, EventArgs e)
                        {
                        ProductsTableAdapter productsAdapter = new
                        ProductsTableAdapter();
                        GridView1.DataSource =
                        productsAdapter.GetProductsByCategoryID(1);
                        GridView1.DataBind();
                        }
                        }
                        


            圖 20: 屬于Beverages(飲料)類(lèi)的所有產(chǎn)品顯示

              第四步:插入,更新和刪除數(shù)據(jù)

              常用的插入,更新和刪除數(shù)據(jù)的模式有兩種。第一種模式,我稱(chēng)之為DB直接模式,涉及的方法被調(diào)用時(shí),會(huì)向數(shù)據(jù)庫(kù)里發(fā)出一個(gè)INSERT, 或UPDATE,或DELETE命令,這個(gè)命令只對(duì)單個(gè)數(shù)據(jù)庫(kù)記錄做操作。象這樣的方法一般接受一系列對(duì)應(yīng)于插入,更新或刪除的值的標(biāo)量參數(shù)(譬如整數(shù),字符串,布爾值,日期時(shí)間等)。譬如,用這個(gè)模式來(lái)操作Products表的話,刪除方法會(huì)接受一個(gè)整數(shù)參數(shù),代表所需要?jiǎng)h除的記錄的ProductID,而插入方法則會(huì)接受一個(gè)對(duì)應(yīng)于ProductName的字符串,對(duì)應(yīng) 于UnitPrice的decimal值,對(duì)應(yīng)于UnitsOnStock的整數(shù)等等。


            圖 21: 每個(gè)插入,更新,和刪除請(qǐng)求都被立刻發(fā)送到數(shù)據(jù)庫(kù)

              另外一個(gè)模式,我稱(chēng)之為批更新模式,可以在一個(gè)方法調(diào)用里更新整個(gè)DataSet,或者整個(gè)DataTable,或 者一個(gè)DataRow集合。在這個(gè)模式里,開(kāi)發(fā)人員在一個(gè)DataTable中刪除,插入,修改DataRow,然后把這 些DataRow或整個(gè)DataTable傳給一個(gè)更新方法。然后這個(gè)方法會(huì)輪循傳入的DataRow們,通過(guò)DataRow的RowState屬 性屬性來(lái)決定這些DataRow是否被改動(dòng)過(guò),或是新記錄,或是被刪除的記錄,然后為每個(gè)記錄發(fā)出合適的 數(shù)據(jù)庫(kù)命令。


            圖 22: 在Update 方法調(diào)用之后,所有的變動(dòng)都與數(shù)據(jù)庫(kù)同步了

              在默認(rèn)情形下,TableAdapter采用批更新模式,但也支持DB直接模式。因?yàn)槲覀冊(cè)趧?chuàng)建我們的TableAdapter時(shí)的高級(jí)選項(xiàng)中選擇了“生成插入,更新,和刪除語(yǔ)句” 這個(gè)選項(xiàng),ProductsTableAdapter 包含了一個(gè) Update()方法,該方法實(shí)現(xiàn)了批 更新模式。具體地說(shuō),TableAdapter包含了一個(gè)Update()<昀敳獴搨 ???oЁCODE> 方法,可以傳入一個(gè)強(qiáng)類(lèi)型 的DataSet,或者一個(gè)強(qiáng)類(lèi)型的DataTable,或者一個(gè)和多個(gè)DataRow。假如你在一開(kāi)始創(chuàng)建TableAdapter時(shí)的選項(xiàng)中沒(méi)有清除“生成DB直接方法(GenerateDBDirectMethods)”復(fù)選框的話,DB直接模 式也會(huì)通過(guò)Insert(),Update()和Delete()方法來(lái)實(shí)現(xiàn)。

              這兩種數(shù)據(jù)修改模式都使用 了TableAdapter的InsertCommand,UpdateCommand, 和DeleteCommand屬性來(lái)向數(shù)據(jù)庫(kù)發(fā)出對(duì)應(yīng) 的INSERT,UPDATE和DELETE命令。你可以在DataSet設(shè)計(jì)器里點(diǎn)擊TableAdapter,然后在屬性窗口查看和改 動(dòng)InsertCommand,UpdateCommand, 和DeleteCommand屬性。(確 認(rèn)你選擇了TableAdapter,并且ProductsTableAdapter對(duì)象是屬性窗口中下拉框里被選中的項(xiàng))


            圖23: TableAdapter包含InsertCommand,UpdateCommand, 和DeleteCommand等屬性

              想查看或改動(dòng)這些數(shù)據(jù)庫(kù)命令的屬性的話,點(diǎn)擊CommandText子屬性,這會(huì)啟動(dòng)對(duì)應(yīng)的查詢(xún) 生成器。


            圖 24: 在查詢(xún)生成器里配置插入,更新,刪除語(yǔ)句

              下面的編碼例子示范了如何使用批更新模式來(lái)把沒(méi)被終止的,且?guī)齑娴扔诨蛏儆?5個(gè)單元的產(chǎn)品的價(jià)格加 倍:

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        
            NorthwindTableAdapters.ProductsTableAdapter
                        productsAdapter =
                        new NorthwindTableAdapters.ProductsTableAdapter();
                        // For each product, double its price if it is not discontinued
                        and
                        // there are 25 items in stock or less
                        Northwind.ProductsDataTable products = productsAdapter.GetProducts();
                        foreach (Northwind.ProductsRow product in products)
                        if (!product.Discontinued && product.UnitsInStock
                        <= 25)
                        product.UnitPrice *= 2;
                        // Update the products
                        productsAdapter.Update(products);
                        

              下面的編碼示范如何使用DB直接模式刪除一個(gè)產(chǎn)品,更新一個(gè)產(chǎn)品,然后添加一個(gè)新的產(chǎn)品:

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        
            NorthwindTableAdapters.ProductsTableAdapter
                        productsAdapter = new
                        NorthwindTableAdapters.ProductsTableAdapter();
                        // Delete the product with ProductID 3
                        productsAdapter.Delete(3);
                        // Update Chai (ProductID of 1), setting the UnitsOnOrder to
                        15
                        productsAdapter.Update("Chai", 1, 1, "10 boxes x 20 bags",
                        18.0m, 39, 15, 10, false, 1);
                        // Add a new product
                        productsAdapter.Insert("New Product", 1, 1,
                        "12 tins per carton", 14.95m, 15, 0, 10, false);
                        
              創(chuàng)建自定義的插入,更新,刪除方法

              用DB直接法生成的Insert(), Update(),和Delete()方法有時(shí) 候會(huì)感覺(jué)有點(diǎn)不方便,特別是當(dāng)數(shù)據(jù)表有許多字段的時(shí)候。看一下前面這個(gè)編碼例子,沒(méi)有IntelliSense的幫 助的話,不是很清楚Products表的哪個(gè)字段對(duì) 應(yīng)Update()和Insert()方法中的哪個(gè)輸入?yún)?shù)。有時(shí)候我們只要更新一到二個(gè)字 段或者需要一個(gè)自定義的Insert()方法,這個(gè)方法需要返回剛插入的記錄 的IDENTITY(自增)的字段值。

              要?jiǎng)?chuàng)建這樣的自定義方法,回到DataSet設(shè)計(jì)器。在TableAdapter上按右鼠標(biāo),選擇“添加查詢(xún)”,然后回 到TableAdapter配置向?qū)АT诘诙辽希覀兛梢灾该饕傻牟樵?xún)的類(lèi)型。讓我們生成一個(gè)添加新 的product(產(chǎn)品)記錄,然后返回新添加記錄的ProductID值的方法。因此,選擇生成一個(gè)插 入(INSERT)型查詢(xún)。


            圖25: 創(chuàng)建一個(gè)給Products表添加新記錄的方法

              下一個(gè)屏顯示InsertCommand的CommandText屬性。在查詢(xún)語(yǔ)句后面,增添一 個(gè)SELECT SCOPE_IDENTITY()的查詢(xún),這查詢(xún)將返回當(dāng)前同一個(gè)操作范圍內(nèi)插 入IDENTITY字段的最后那個(gè)identity 值。(詳見(jiàn)技術(shù)文檔中關(guān) 于SCOPE_IDENTITY()的內(nèi)容以及為什么你應(yīng)該使用SCOPE_IDENTITY()而不是 @@IDENTITY)。確認(rèn)在添加SELECT語(yǔ)句前,你在INSERT語(yǔ)句后面添一個(gè)分號(hào) 。


            圖26: 增添查詢(xún)返回SCOPE_IDENTITY()值

              最后,把這個(gè)新方法命名為InsertProduct。


            圖 27:放方法名字設(shè)成InsertProduct

              當(dāng)你返回DataSet設(shè)計(jì)器時(shí),你將看到ProductsTableAdapter多了一個(gè)新的方 法,InsertProduct。如果對(duì)應(yīng)Products表的每個(gè)字段,這個(gè)新的方法沒(méi)有對(duì)應(yīng)的參數(shù)的話,非常可能的原因是,你忘了給INSERT語(yǔ)句的結(jié)尾添加一個(gè)分號(hào)(semi-colon)。重新配 置InsertProduct方法,確認(rèn)在INSERT和SELECT語(yǔ)句間有個(gè)分號(hào)。

              在默認(rèn)情形下,插入方法調(diào)用的是非查詢(xún)(non-query)方法,意即,他們只返回受影響的記錄數(shù)。但是,我們想要讓InsertProduct方法返回一個(gè)查詢(xún)返回的值,而不是受影響的記錄數(shù)。這可以把InsertProduct方法的ExecuteMode屬性改 成Scalar(標(biāo)量)來(lái)實(shí)現(xiàn)。


            圖 28:把ExecuteMode屬性改成Scalar

              下面的編碼示范如何使用這個(gè)新的InsertProduct方法:

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        
            NorthwindTableAdapters.ProductsTableAdapter
                        productsAdapter = new
                        NorthwindTableAdapters.ProductsTableAdapter();
                        // Add a new product
                        int new_productID =
                        Convert.ToInt32(productsAdapter.InsertProduct("New
                        Product", 1, 1, "12 tins per carton",
                        14.95m, 10, 0, 10, false));
                        // On second thought, delete the product
                        productsAdapter.Delete(new_productID);
                        
              第五步:完成數(shù)據(jù)訪問(wèn)層

              注意,ProductsTableAdapters類(lèi)從Products表中返回的 是CategoryID和SupplierID的值,但并不包括Categories表 的CategoryName字段和Suppliers表的CompanyName字段,盡管當(dāng) 我們顯示產(chǎn)品信息時(shí),這些很可能是我們想要顯示的字段。我們可以擴(kuò)充TableAdapter的起始方 法GetProducts()來(lái)包含CategoryName和CompanyName字段的值, 這方法進(jìn)而會(huì)更新強(qiáng)類(lèi)型的DataTable來(lái)包括這些新的字段。

              但這會(huì)造成一個(gè)問(wèn)題,因?yàn)門(mén)ableAdapter的插入,更新,刪除數(shù)據(jù)的方法是基于這個(gè)起始方法的,幸運(yùn)的是, 自動(dòng)生成的插入,更新,刪除方法并不會(huì)受SELECT子句中的子查詢(xún)的影響。如果我們注意把 對(duì)Categories和Suppliers的查詢(xún)添加成子查詢(xún),而不是用JOIN語(yǔ) 句的話,我們可以避免重做這些修改數(shù)據(jù)的方法。在ProductsTableAdapter中的GetProducts()方法上按右鼠標(biāo),選擇“配置”,然后,把SELECT子句改成:

            SQL
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        
            SELECT     ProductID, ProductName, SupplierID, CategoryID,
                        QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued,
                        (SELECT CategoryName FROM Categories
                        WHERE Categories.CategoryID = Products.CategoryID) as CategoryName,
                        (SELECT CompanyName FROM Suppliers
                        WHERE Suppliers.SupplierID = Products.SupplierID) as SupplierName
                        FROM         Products
                        


            圖29: 更新GetProducts()方法的SELECT語(yǔ)句

              在更新GetProducts()方法使用這個(gè)新查詢(xún)語(yǔ)句之后,對(duì)應(yīng)的DataTable將包含2個(gè)新字段,CategoryName和SupplierName。


            圖30: Products DataTable多了2個(gè)新字段

              花點(diǎn)時(shí)間把GetProductsByCategoryID(categoryID)方法中的SELECT 子句也更新一下。

              如果你使用JOIN句法更新GetProducts()中的SELECT語(yǔ)句的話 ,DataSet設(shè)計(jì)器不能使用DB直接模式自動(dòng)生成插入,更新,以及刪除數(shù)據(jù)庫(kù)記錄的方法。你必須手工生成這 些方法,就象本教程早先時(shí)候我們對(duì)InsertProduct方法的做法一樣。此外,你必須手工提供 InsertCommand,UpdateCommand和DeleteCommand屬性值,假如你 想使用批更新模式的話。
              添加其他的TableAdapter

              到目前為止,我們只討論了針對(duì)單個(gè)數(shù)據(jù)表的單個(gè)TableAdapter。但是,Northwind數(shù)據(jù)庫(kù)里含有我們需要在 我們的web應(yīng)用中使用的幾個(gè)相關(guān)的表。一個(gè)強(qiáng)類(lèi)型的DataSet可以包含多個(gè)相關(guān)的DataTable。因此,為了完 成我們的DAL,我們需要為這些我們將來(lái)要用到的數(shù)據(jù)表添加相應(yīng)的DataTable。步驟如下,打開(kāi) DataSet設(shè)計(jì) 器,在設(shè)計(jì)器上按右鼠標(biāo),選擇“添加/TableAdapter”。這會(huì)生成一個(gè)新的DataTable和TableAdapter,然后我 們?cè)缦扔懻撨^(guò)的配置向?qū)?huì)指引你完成配置。

              花上幾分鐘,創(chuàng)建對(duì)應(yīng)于下列查詢(xún)的TableAdapter及其方法。注意,ProductsTableAdapter的查詢(xún)中包含了用以獲取每個(gè)產(chǎn)品的分類(lèi)和供應(yīng)商名字的子查詢(xún)。另外,如果你是隨著教程在做的話,你已經(jīng)添加過(guò)ProductsTableAdapter類(lèi) 的GetProducts()和GetProductsByCategoryID(categoryID)方法了。
            • ProductsTableAdapter
              • GetProducts:

                SELECT ProductID, ProductName, SupplierID, CategoryID,
                QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
                ReorderLevel, Discontinued , (SELECT CategoryName FROM
                Categories WHERE Categories.CategoryID =
                Products.ProductID) as CategoryName, (SELECT CompanyName
                FROM Suppliers WHERE Suppliers.SupplierID =
                Products.SupplierID) as SupplierName
                FROM Products
              • GetProductsByCategoryID:

                SELECT ProductID, ProductName, SupplierID, CategoryID,
                QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
                ReorderLevel, Discontinued , (SELECT CategoryName FROM
                Categories WHERE Categories.CategoryID =
                Products.ProductID) as CategoryName,
                (SELECT CompanyName FROM Suppliers WHERE
                Suppliers.SupplierID = Products.SupplierID) as SupplierName
                FROM Products
                WHERE CategoryID = @CategoryID
              • GetProductsBySupplierID

                SELECT ProductID, ProductName, SupplierID, CategoryID,
                QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
                ReorderLevel, Discontinued ,
                (SELECT CategoryName FROM Categories WHERE
                Categories.CategoryID = Products.ProductID)
                as CategoryName, (SELECT CompanyName FROM Suppliers
                WHERE Suppliers.SupplierID = Products.SupplierID)
                as SupplierName
                FROM Products
                WHERE SupplierID = @SupplierID
              • GetProductByProductID

                SELECT ProductID, ProductName, SupplierID, CategoryID,
                QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
                ReorderLevel, Discontinued , (SELECT CategoryName
                FROM Categories WHERE Categories.CategoryID =
                Products.ProductID) as CategoryName,
                (SELECT CompanyName FROM Suppliers
                WHERE Suppliers.SupplierID = Products.SupplierID)
                as SupplierName
                FROM Products
                WHERE ProductID = @ProductID

            • CategoriesTableAdapter
              • GetCategories

                SELECT CategoryID, CategoryName, Description
                FROM Categories
              • GetCategoryByCategoryID

                SELECT CategoryID, CategoryName, Description
                FROM Categories
                WHERE CategoryID = @CategoryID

            • SuppliersTableAdapter
              • GetSuppliers

                SELECT SupplierID, CompanyName, Address, City,
                Country, Phone
                FROM Suppliers
              • GetSuppliersByCountry

                SELECT SupplierID, CompanyName, Address,
                City, Country, Phone
                FROM Suppliers
                WHERE Country = @Country
              • GetSupplierBySupplierID

                SELECT SupplierID, CompanyName, Address,
                City, Country, Phone
                FROM Suppliers
                WHERE SupplierID = @SupplierID

            • EmployeesTableAdapter
              • GetEmployees

                SELECT EmployeeID, LastName, FirstName,
                Title, HireDate, ReportsTo, Country
                FROM Employees
              • GetEmployeesByManager

                SELECT EmployeeID, LastName, FirstName,
                Title, HireDate, ReportsTo, Country
                FROM Employees
                WHERE ReportsTo = @ManagerID
              • GetEmployeeByEmployeeID

                SELECT ployeeID, LastName, FirstName,
                Title, HireDate, ReportsTo, Country
                FROM Employees
                WHERE EmployeeID = @EmployeeID


            圖31:添加了四個(gè)TableAdapter后的DataSet設(shè)計(jì)器
              給DAL添加定制編碼

              添加到強(qiáng)類(lèi)型DataSet中的TableAdapter和DataTable是在一個(gè)XML Schema定義文 件(Northwind.xsd)中定義的。你可以在解決方案資源管理器里在Northwind.xsd 文件上按右鼠標(biāo),選擇“查看編碼(View Code)”,打開(kāi)這個(gè)Schema文件來(lái)查看其中內(nèi)容。


            圖32:Northwinds強(qiáng)類(lèi)型DataSet的XML Schema定義文件

              這個(gè)schema信息在設(shè)計(jì)時(shí)編譯之后會(huì)被翻譯成C#或Visual Basic 編碼,或者如果有必要的話,會(huì)在運(yùn)行時(shí) 翻譯,然后你就能在調(diào)試器里單步遍歷執(zhí)行。想查看這些自動(dòng)生成的編碼的話,在類(lèi)視圖里,展 開(kāi)TableAdapter 類(lèi)或者強(qiáng)類(lèi)型的DataSet 類(lèi)。如果在屏幕上看不到類(lèi)視圖的話,在“查看”(View)菜單里選擇“ 類(lèi)視圖”,或者按鍵組合Ctrl+Shift+C。在類(lèi)視圖里,你能看到強(qiáng)類(lèi)型的DataSet類(lèi)和TableAdapter類(lèi)的屬性,方法和事件。想看某個(gè)特定的方法的編碼話,在類(lèi)視圖雙擊對(duì)應(yīng)方法的名字或者在方法上按右鼠標(biāo),選 擇“移至定義區(qū)(Go To Definition)”。


            圖33:在類(lèi)視圖里選擇“移至定義區(qū)(Go To Definition)”,查看自動(dòng)生成的編碼

              雖然自動(dòng)生成的編碼省時(shí)省力,但這樣的編碼往往是非常通用化的(generic),為滿(mǎn)足一個(gè)應(yīng)用程序特有的需 求需要做些定制。但擴(kuò)展自動(dòng)生成的編碼的風(fēng)險(xiǎn)在于,如果生成這些編碼的工具決定該是重新生成這些編碼的 時(shí)候了,則會(huì)把你定制的編碼沖掉。使用.NET 2.0中的一個(gè)新的部分(partial)類(lèi)的概念,很容易將一個(gè)類(lèi)的 定義分寫(xiě)在幾個(gè)文件里。這允許我們給自動(dòng)生成的類(lèi)添加我們自己的方法,屬性,和事件,而不用擔(dān)心Visual Studio會(huì)沖掉我們的定制編碼。

              為示范如何定制DAL起見(jiàn),讓我們來(lái)給SuppliersRow 添加一個(gè)GetProducts()方法。這 個(gè)SuppliersRow類(lèi)代表了Suppliers表的個(gè)別記錄,每個(gè)供應(yīng)商(supplier)可以 提供0個(gè)到多個(gè)產(chǎn)品,所以GetProducts()將返回指定的供應(yīng)商的這些產(chǎn)品。做法如 下,在App_Code文件夾里添加一個(gè)新的類(lèi)文件,將其命名為SuppliersRow.cs, 然后在其中添加下列編碼:

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        
            using System;
                        using System.Data;
                        using NorthwindTableAdapters;
                        public partial class
                        Northwind
                        {
                        public partial class
                        SuppliersRow
                        {
                        public Northwind.ProductsDataTable GetProducts()
                        {
                        ProductsTableAdapter productsAdapter =
                        new ProductsTableAdapter();
                        return
                        productsAdapter.GetProductsBySupplierID(this.SupplierID);
                        }
                        }
                        }
                        

              這個(gè)部分(partial)類(lèi)指示編譯器在編譯Northwind.SuppliersRow類(lèi)時(shí),應(yīng)該包含我們剛定義的這個(gè)GetProducts()方法。如果你編譯你的項(xiàng)目,然后返回類(lèi)視圖,你就會(huì)看到GetProducts()已被列為Northwind.SuppliersRow的一個(gè)方法。


            圖34: GetProducts()方法成為Northwind.SuppliersRow類(lèi)的一部 分

              GetProducts()方法現(xiàn)在就能用來(lái)枚舉一個(gè)指定供應(yīng)商的產(chǎn)品列單,如下列編碼所示:

            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        
            NorthwindTableAdapters.SuppliersTableAdapter
                        suppliersAdapter = new
                        NorthwindTableAdapters.SuppliersTableAdapter();
                        // Get all of the suppliers
                        Northwind.SuppliersDataTable suppliers =
                        suppliersAdapter.GetSuppliers();
                        // Enumerate the suppliers
                        foreach (Northwind.SuppliersRow supplier in suppliers)
                        {
                        Response.Write("Supplier: " +
                        supplier.CompanyName);
                        Response.Write("<ul>");
                        // List the products for this supplier
                        Northwind.ProductsDataTable products = supplier.GetProducts();
                        foreach (Northwind.ProductsRow product in products)
                        Response.Write("<li>" +
                        product.ProductName + "</li>");
                        Response.Write("</ul><p>&nbsp;</p>");
                        }
                        

              This data can also be displayed in any of ASP.NET's data Web controls. The following page uses a GridView control with two fields:數(shù)據(jù)也可以在任何一種ASP.NET的Web控件中顯示。下面這個(gè)網(wǎng)頁(yè) 使用了含有2個(gè)字段的GridView 控件:
            • 一個(gè)BoundField用以顯示每個(gè)供應(yīng)商的名字,
            • 另一個(gè)TemplateField,包含了一個(gè)BulletedList控件,用來(lái)綁定針對(duì)每個(gè)供應(yīng)商調(diào)用 的GetProducts()方法返回的結(jié)果
              我們將在以后的教程里討論怎樣來(lái)顯示這樣的主/從(master-detail)報(bào)表。在這里,這個(gè)例子的目的是用 來(lái)示范如何使用添加到Northwind.SuppliersRow類(lèi)中的自定義的方法的。

            SuppliersAndProducts.aspx
            ASP.NET
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        23
                        24
                        25
                        26
                        27
                        28
                        29
                        30
                        31
                        32
                        33
                        34
                        35
                        36
                        37
                        38
                        39
                        40
                        41
                        
            <%@ Page Language="C#"
                        AutoEventWireup="true" CodeFile="SuppliersAndProducts.aspx.cs"
                        Inherits="SuppliersAndProducts" %>
                        <!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>
                        Suppliers and Their Products</h1>
                        <p>
                        <asp:GridView ID="GridView1" runat="server"
                        AutoGenerateColumns="False"
                        CssClass="DataWebControlStyle">
                        <HeaderStyle CssClass="HeaderStyle" />
                        <AlternatingRowStyle CssClass="AlternatingRowStyle" />
                        <Columns>
                        <asp:BoundField DataField="CompanyName"
                        HeaderText="Supplier" />
                        <asp:TemplateField HeaderText="Products">
                        <ItemTemplate>
                        <asp:BulletedList ID="BulletedList1"
                        runat="server" DataSource="<%#
                        ((Northwind.SuppliersRow)((System.Data.DataRowView)
                        Container.DataItem).Row).GetProducts() %>"
                        DataTextField="ProductName">
                        </asp:BulletedList>
                        </ItemTemplate>
                        </asp:TemplateField>
                        </Columns>
                        </asp:GridView>
                        &nbsp;</p>
                        </div>
                        </form>
                        </body>
                        </html>
                        

            SuppliersAndProducts.aspx.cs
            C#
            1
                        2
                        3
                        4
                        5
                        6
                        7
                        8
                        9
                        10
                        11
                        12
                        13
                        14
                        15
                        16
                        17
                        18
                        19
                        20
                        21
                        22
                        
            using System;
                        using System.Data;
                        using System.Configuration;
                        using System.Collections;
                        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;
                        public partial class
                        SuppliersAndProducts : System.Web.UI.Page
                        {
                        protected void
                        Page_Load(object sender, EventArgs e)
                        {
                        SuppliersTableAdapter suppliersAdapter = new
                        SuppliersTableAdapter();
                        GridView1.DataSource = suppliersAdapter.GetSuppliers();
                        GridView1.DataBind();
                        }
                        }
                        


            圖 35: 供應(yīng)商的公司名字列在左欄,他們的產(chǎn)品列在右欄

              總結(jié)

              構(gòu)造web應(yīng)用時(shí),創(chuàng)建DAL應(yīng)該是你最先做的步驟之一,應(yīng)該在你開(kāi)始創(chuàng)建表現(xiàn)層之前進(jìn)行。使用Visual Studio的話,創(chuàng)建基于強(qiáng)類(lèi)型DataSet的DAL是個(gè)可以不寫(xiě)一行編碼,在10到15分鐘內(nèi)就可完成的任務(wù)。以后的 教程將建立在這個(gè)DAL基礎(chǔ)之上。在下一個(gè)教程里,我們將定義一堆業(yè)務(wù)規(guī)則,然后看一下如何在一個(gè)分開(kāi)的 業(yè)務(wù)邏輯層里實(shí)現(xiàn)這些規(guī)則。
            posted on 2007-11-15 20:37 獨(dú)孤九劍 閱讀(144) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): Learn articles
            精品久久久久久无码中文字幕 | 亚洲人成网亚洲欧洲无码久久| 性做久久久久久久久| 人妻精品久久无码区| 久久国产高清一区二区三区| 久久婷婷国产剧情内射白浆| 久久国产乱子精品免费女| 日本五月天婷久久网站| 亚洲一本综合久久| 亚洲AV无一区二区三区久久| 国产亚洲成人久久| 久久99国产精品久久久| 久久久久久久波多野结衣高潮| 99久久夜色精品国产网站| 久久精品国产清自在天天线 | 99久久精品免费看国产一区二区三区 | 久久久久免费精品国产| 色偷偷888欧美精品久久久| 色8久久人人97超碰香蕉987| 久久亚洲精品无码播放| 国产AV影片久久久久久| 国产V亚洲V天堂无码久久久| 漂亮人妻被中出中文字幕久久 | 无码专区久久综合久中文字幕| 久久亚洲AV无码西西人体| 国产精品免费久久久久电影网| 99久久精品午夜一区二区| 久久久久久国产精品无码超碰| 99久久精品国产一区二区| 精品久久久久久久久免费影院| 久久久久久青草大香综合精品| 国产精品成人99久久久久 | 亚洲综合伊人久久大杳蕉| 久久精品国产99国产精品亚洲| 精品久久久久成人码免费动漫| 狠狠色丁香久久婷婷综合_中| 无码国内精品久久人妻麻豆按摩 | 色狠狠久久AV五月综合| 久久久久久亚洲Av无码精品专口| 久久精品中文字幕大胸| 精品国产青草久久久久福利|