asp.net|visual|資料
"Never put off until run time what can be done at compile time."
David Gries, Compiler Construction for Digital Computers
Introduction
作為程式員,我們在學習一些新技術的時候,範例有時候會是我們最大的敵人。指南通常被設計成簡單易懂,但同時裡面的懶惰、無效率的甚至是危險的代碼編寫會增多。像這種情況最普遍存在的就是在ADO.NET的範例中了。在這篇文章中,我們將看一下資料庫中的強型別對象有什麼意義,會讓你在你的程式中這樣做,儘管缺乏範例。
有點特別的是,我們將看到在Visual Studio 2005中是如何建立和使用強型別資料集的。正如這篇文章所探究的,與另外一種弱類型資料存取技術相比,強型別資料集提供了許多有利之處。我們也會在這裡看到,用Visual Studio 2005建立和使用強型別資料集並沒有變得更簡單。想學更多就繼續看下去吧。
The Basics and Benefits of Strongly-Typed Objects
要想明白強型別是什麼意思,你可以先想想約會。如果你是單身,你會考慮跟哪種類型的人約會呢?你可能有一些特定的標準(比如健康和有魅力),又或者標準很簡單或並不是很明確。無論你的條件是什麼,當你決定更多地與誰一起的時候,你總會用自己對這一些類型的一定的標準去衡量考慮。如果你很聰明,你會想一大堆來保護自己不受感情創傷。你可能會發現,比如說,與一個酒鬼相處是很不穩定,除非兩人之間有一個認真的關係。但是,讓一個人改變是很痛苦並且非常困難的。因此,你的智慧會指示你讓你在這段關係開始前就叫停。給你的約會標準裡加一個不喝酒的條款會保護你不會在未來心痛,並且讓你可以更專心的把你的時間和精力放在更好的候選人身上。
你可能在驚訝這個推理與編程有什麼關係。沒關係,跟我來吧,可愛的讀者!ADO.NET資料存取對象是被設計成極富彈性的。當你從資料庫中讀取資料時,你可能是用許多平常.NET framework允許的的通用類型的對象在工作,除非遇到特殊的問題。應用我們的約會理論,基本上可以把你的相關資料看作是通用對象。“我約會的只要不是太麻煩的就好了。”難道你就不能再明確一點嗎?甚至連是人還是其它生物都沒有限制!作為你的朋友,我懇求你,“多點標準吧!讓你的清單縮小一點!”
正如你如果忽視約會的對象是誰會導致將來的關係問題一樣,在你的代碼中放任你的objects也會造成一些錯誤。並且,如果你讓舊的object在你的子程式中漫舞,你可能直到程式運行執行時才會發現這是個問題。用我們的約會理論來看,在運行時捕捉錯誤就好像你的約會在一間新潮的意大利餐館中間發生痛苦和難堪的爭吵一樣。是的,你發現了,如果你在之前先有計劃,你就不會在一堆用餐者的注視中結束這個場面,也不會很難堪。只要在你的代碼裡簡單地應用一些嚴格點的標準,你就可以在程式開始編譯前捕捉到錯誤。比如下面這句代碼例子:
string FirstName = myrow.("FirstName").ToString();
這個例子中的DataRow是無類型的,結果就是,你必須要用列的名字作字串去得到你所需要的值(或者你可以選用這個列在記錄的列集合中的索引)。好在那一列確實存在。DataRow的列的資料類型是object,我們假定這個FirstName列下面的資料類型是string,而且我們在使用之前必須要把它顯式轉換成string。如果這一列的名字發生變化(例如變成PersonFirstName),編譯器並沒有辦法通知你。鬱悶吧?但你可以不這樣的。如果你的代碼像下面這樣,你的生活就會更簡單,你的代碼就會更可靠。
string FirstName = PersonRow.FirstName;
在這第二個例子中,我們用一個強型別的行,並且我們知道FirstName屬性是string類型的。沒有淩亂的列名,也沒有亂七八糟的類型轉換。編譯器已經為我們做了類型檢查,我們可以放心的進行其它工作,而絲毫不用擔心是否把列名敲對了。
其它所有的東西都是一樣的,所以你肯定會毫不猶豫地使用這種方式,而不再使用通用類型的方式。但請等一下,強型別objects是從哪裡來的?我也希望我可以告訴你這些objects是自動建立的。但是,正如良好的關係需要時間和精力一樣,讓你的objects強型別也需要額外的努力。但花在這裡的額外時間絕對是值得的,它也節省了在未來“捉臭蟲”時花費的更多的指數級的時間。
完成強型別有好幾種方法,我們將在這篇文章餘下的部分介紹如何在Visual Studio 2005中建立強型別的資料集。我們也會把這種做法與其它做法的優缺點作一個比較。
Creating Strongly-Typed DataSets in Visual Studio 2005
強型別資料集其實只是把普通資料集的列和表預先定義好,所以編譯器已經知道它們包含什麼。取代你好像帶著棒球手套弄的鬆散的封裝,強型別資料集正像一個非常合適的手套。而Visual Studio的每一次連續的版本都使得資料集強型別化的處理更加簡單。在下面這個例子中,我們將使用SQL Server 2005的AdventureWorks資料庫。簡單地執行下面一些步驟:
1. 開啟Visual Studio,建立一個新的ASP.NET網站。
2. 在Solution Explorer視窗,右鍵點擊新增一個項,選擇DataSet。給其命名為AdventureWorks.xsd(見截圖)。Visual Studio將推薦你把DataSet檔案放進App_Code檔案來,你只要點同意就可以了。
3. 開啟AdventureWorks.xsd之後是設計模式,TableAdapter設定精靈將會運行。這時候,點取消,我們將從Server Explorer中把所要的表拖進來。
4. 在Server Explorer工具列中瀏覽找到AdventureWorks資料庫。(如果你還沒有安裝AdventureWorks資料庫,你可以去微軟的下載頁面SQL Server 2005 Samples and Sample Databases下載它和一些其它的SQL Server 2005樣本)
5. 把SalesOrderHeader表和SalesOrderDetail表拖進DataSet的設計視窗。視窗應該會像截圖中一樣。我們看到的是什麼呢?每當我們增加一個表,Visual Studio就會建立一個強型別DataTable(名字和原來的表一樣)和一個TableAdapter。這個DataTable已經為我們定義好每一列。TableAdapter是我們用來填充表的,預設有一個Fill()方法從原表中得到每一行資料。
照原來的樣子的話,這個強型別資料集將會返回這兩個表的所有記錄。但是AdventureWorks資料庫包含了許多訂單資訊,因此為什麼不建立一個更明確的查詢呢?我們可以給TableAdapter對象增加方法來擷取一個特定的子記錄集。右鍵點擊SalesORderHeaderTableAdapter,然後選擇Add|Query。選擇“Use SQL statements”後點下一步,然後選擇“SELECT which returns rows”再點下一步。最近,在視窗中輸入下面的查詢語句(或者可以使用Query Builder來完成這項工作):
SELECT
SalesOrderID, RevisionNumber, OrderDate, DueDate, ShipDate,
Status, OnlineOrderFlag, SalesOrderNumber, PurchaseOrderNumber,
AccountNumber, CustomerID, ContactID, SalesPersonID, TerritoryID,
BillToAddressID, ShipToAddressID, ShipMethodID, CreditCardID,
CreditCardApprovalCode, CurrencyRateID, SubTotal, TaxAmt, Freight,
TotalDue, Comment, rowguid, ModifiedDate
FROM Sales.SalesOrderHeader
WHERE (OrderDate > @OrderDate)
這個SQL查詢是一個簡單的SELECT查詢,用了一個@OrderDate參數以篩選結果。這將使我們不用返回資料庫中的所有記錄。保持“Fill a DataTable”和“Return a DataTable”複選框的選中,點完成。把這個SELECT語句加完之後你的設計器現在應該像截圖一樣,在SalesOrderHeaderTableAdapter下面多了一個查詢。
強型別資料集建立起來以後,我們就可以輕易地用幾行代碼在ASP.NET頁面中把資料顯示出來。在網站裡建立一個ASP.NET頁面並轉到設計模式。拖一個GridView控制項到上面,保留它的ID為GirdView1。然後到原始碼頁中,在檔案的上方將AdventureWorksTableAdapters命名空間引入(在c#裡面文法是using AdventureWorksTableAdapters;)。最後在Page_Load事件裡增加下面的代碼:
// Create the SalesOrderHeaderTableAdapter
SalesOrderHeaderTableAdapter salesAdapter =
new SalesOrderHeaderTableAdapter();
// Get orders that took place after July 1st, 2004
AdventureWorks.SalesOrderHeaderDataTable Orders =
salesAdapter.GetDataBy(new DateTime(2004, 7, 1));
// Bind the order results to the GridView
this.GridView1.DataSource = Orders;
this.GridView1.DataBind();
代碼非常簡單。我們建立一個SalesORderHeaderTableAdapter的執行個體以填充資料表。這裡要注意的是,不同於普通的DataTable,我們聲明了一個SalesORderHeaderDataTable類型的對象,我們調用GetDateBy()方法,傳遞一個DateTime對象來填充資料。這裡也要注意,擷取的命令也是強型別的,因此我們必須傳遞一個DateTime對象,而不是一個普通的對象。下面的截圖即是上面程式碼範例的結果。
除了用代碼把結果集綁定到GridView外,你也可以用一個ObjectDataSource,把它的TypeName屬性設成AdventureWorksTableAdapters.SalesOrderHeaderTableAdapter,把它的SelectMethod設定成GetData或者GetDataBy。
除了串連資料庫不需要寫代碼之外,使用強型別資料集的另一大優點是不存在編譯器無法檢查的潛伏在我們的代碼中的列名字串。我們也不需要進行任何類型轉換。如果資料庫結構描述發生改變,只要更新AdventureWorks.xsd檔案,我們就會發現所有相關的改變在編譯時間自動完成了。
Other Techniques for Generating Strongly-Typed Data-Access Applications
除了使用強型別資料集之處,還有其它的方法可以在你的程式中實現強型別。你可以建立比DataSets更輕量級並且更符合你資料庫的自訂類。也有一些第三方軟體開發人員開發了自動完成這一過程的工具。其中一個比較特別的也是我比較喜愛的是LLBLGen Pro,我曾經寫過關於它的一本書:Rapid C# Windows Development: Visual Studio 2005, SQL Server 2005, and LLBLGen Pro。(你可以在我的網站上免費閱讀此書1/3的內容。)另一個很歡迎的工具是CodeSmith。甚至微軟也在開發一個叫DLINQ的小工具,但仍在測試之中,估計至少要等一下年才會推出。
如果你使用Visual Studio的強資料集方法,不容置疑,其中一個優點便是你不需要購買其它軟體。所有的這些解決方案都有不同的特點和好處,但最主要的好處是可靠,錯誤少,花更少的時間調試。也更容易去檢查資料庫結構描述改變所造成的影響並作維護。希望你已經認識到強型別的好處。祝開發好運(約會也是)!
By Joseph Chancellor
Attachments
Download the code examined in this article
About the Author
Joseph Chancellor is a C# developer in Southern California who has had his fair share of relational trauma. He appreciates all kinds of feedback and suggestions. Visit his blog or read the first five chapters of his book on Visual Studio 2005, SQL Server 2005, and LLBLGen Pro.