"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 suggestions. Visit his blog or read the first five chapters of his book on Studio 12050 LLBLGen Pro.
原文網址:http: //aspnet.4guysfromrolla.com/articles/020806-1.aspx