掌握ADO.NET的十個熱門技巧(二)
2024-07-10 13:02:46
供稿:網友
7. adox可以幫你得到并改變schema信息
ado.net并沒有為得到并管理schema信息提供一個完全的對象模式。你應該用activex data objects extensions for data definition language and security (adox)或用每個數據庫提供的本地功能來得到并改變schema信息。adox是ado對象的一個擴展,它包括用來創建和修改schema的對象。你可以編寫適用于各種數據源的代碼(不管本地語法有什么不同),因為adox是管理schema的一個基于對象的方法。
你可以用一個data reader對象來讀(不是設置)簡單的schema信息。所有的data reader類(oledbdatareader、sqldatareader、oracledatareader)都提供了一個getschematable方法,該方法可以讀取查詢到的列的元數據信息。getschematable返回一個datatable對象(格式是每列一行)和固定的一組包含信息的列。返回的元數據可以分成三類:列元數據、數據庫特征和列屬性。返回的列可以是allowdbnull、isautoincrement、columnname、isexpression、isreadonly和numericprecision等。在msdn資料中有完整的列表(見附加資源)。
在調用executereader時,如果你執行keyinfo命令,那么getschematable方法就可以返回更精確的數據。你可以將keyinfo行為同缺省的行為結合起來,執行一個單獨的命令并得到schema和數據:reader = cmd.executereader( _
commandbehavior.keyinfo or _
commandbehavior.closeconnection)
只有執行keyinfo,iskey、basetablename、isaliased、isexpression和ishidden字段的值才能被正確返回。如果執行keyinfo,關鍵的列(如果有)通常是添加在結果集的底部的,但不給它們返回數據。
8. 用一個派生的類和自定義的串行化來節省空間
只有兩個ado.net對象是被標記為可串行化的——datatable和dataset。.net framework中的串行化是通過formatter對象來完成的,它們可以將一個對象實例保存到一個二進制或一個soap流(stream)中。.net formatter用reflection來提取任何必要的信息。然而,如果這個類實現了iserializable接口,那么.net formatter就會給接口的方法讓步,讓它們負責拷貝需要串行化到一個內存緩沖器中的所有的信息。datatable和dataset類都通過iserializable接口支持串行化。
如果你將一個datatable或一個dataset串行到一個二進制(binary stream)中,你應該可以得到非常緊湊的輸出結果。雖然你得到的結果文件是最小的,但遺憾的是,它實際上并不小。荒謬的是,你保存到一個二進制的dataset比你用writexml方法保存到xml的同樣的dataset要大很多。
要解釋這種情況,我們需要來看看ado.net對象是用什么方式被串行起來的。在串行一個dataset對象時,它將基于xml的diffgram表示法保存在formatter的緩沖器中。在串行一個datatable時,它首先創建了一個臨時的dataset對象,將它定義為它的parent,然后作為一個diffgram串行起來。
一個diffgram是一個xml流,它提供了一個dataset中表和行的有狀態的表示法。一個diffgram文件是很詳細的,有些冗長。diffgram包含當前的數據,以及被修改的行和未解決的錯誤的初始值。當我們保存一個dataset或一個datatable時,所有這些信息就會被傳遞給serializer。被串行化的對象總是包含xml數據,因此即使當輸出流是二進制的時,最后的輸出結果仍然會很大。
你可以創建一個繼承datatable或dataset的新的可串行化的類來解決這個問題,并且更有效地保存ado.net對象。你必須用<serizlizable()>屬性來標記新類,即使父類是可以串行化的。實際上,串行性(serizlizability)并不是一個可以自動繼承的類屬性。你從datatable或dataset構建的新類也可以實現iserializable接口。當然,你可以為新類選擇一個不同的串行化方案。一個簡單而有效的方法就是將datatable類的所有成員映射到數組和值成員中(見列表1)。
運用一個派生的類和一個自定義的串行化方案可以為一個dataset對象節省多達80%的磁盤空間。節省的空間的比率取決于dataset中的數據類型。你的數據越基于文本,節省的空間越多。然而,運用二進制的blob字段只可以節省大約25%的空間(下載一個完整的例子)。
9. 選擇一個適合你的數據的分頁機制
datagrid服務器控件使我們可以更容易地在web應用程序中以長度可變的頁面來顯示數據了。該控件有綁定和格式化功能,它可以接受一個ado.net數據對象并為瀏覽器生成html代碼。出于性能的原因,在頁面的視圖狀態,datagrid并沒有緩存數據源的內容。因此,當返回頁面時,你就必須填充grid。要實現這一點可以用兩種方法:在web服務器上將數據源作為整體或一部分緩存起來,然后讀回;或者對每個請求從物理數據庫加載所需的記錄。如果你選擇第一種方法,那么數據就從存儲中只被讀取一次,保存在一個緩存中,并為以后的postback事件讀回。我們通常用內存中的全局對象(如session或cache)來保存這個數據。我們用dataset來搜集所有需要的數據并將它保存在內存中。將一個dataset對象保存在session中同ado中的線程含義并不一樣,但是通過減少web服務器可用的內存仍可以影響可擴展性。
如果要顯示的數據是特定于session的,那么在每次返回頁面時加載記錄頁面就比用一個dataset和asp.net全局對象來緩存數據要好。編寫得很好的sql代碼可以將結果集分成許多頁,再加上datagrid控件內置的自定義分頁機制,我們就可以得到最佳的解決方案來保持asp.net應用程序的可擴展性和良好的性能了。
對于windows應用程序,我的建議正好相反。臺式應用程序很適合應用斷開的編程模式(dataset和其它ado.net對象使這種模式變得更簡單了)。當然,這并不意味著,你可以在客戶端無憂無慮地下載成千上萬的記錄。盡管你可以將ado.net對象用于任何種類的.net應用程序,但如何使用它們是隨具體情況的不同而不同的。
10. 訪問多個結果集
根據查詢的語法,你可以返回多個結果集。缺省情況下,data reader是位于第一個結果集上的。你可以用read方法在當前結果集中滾動查看記錄。在找到最后一個記錄時,read方法返回false,不再繼續讀取。你應該用nextresult方法轉移到下一個結果集。如果沒有更多的需要讀的結果集了,那么該方法返回false。下面的代碼說明了如何在所有返回的結果集中訪問所有的記錄:dim reader as sqldatareader
cmd.connection.open()
reader = cmd.executereader()
do
' move through the first resultset
while reader.read()
' access the row
end while
loop while reader.nextresult()
reader.close()
cmd.connection.close()
當你讀一個行的內容時,可以通過索引或名稱來識別列。運用索引可以更快,因為提供者可以直接進入到緩沖器中。如果你指定列名,提供者就用getordinal方法將名稱轉換成相應的索引,然后執行基于索引的訪問。注意,對于sql server data reader來說,所有的getxxx方法實際上都調用了相應的getsqlxxx方法。對于oracle data reader來說,情況是類似的,本地數據總是被寫進.net framework類型中。oracledatareader類為它自己的內部類型提供了一組私有的getxxx方法。這些方法包括getoraclebfile、getoraclebinary和getoracledatetime等。相反,ole db和odbc readers只有單獨的一組get方法。
.net framework 1.1版通過添加方法hasrows擴展了data readers的編程接口,該方法返回一個boolean值來說明是否有很多行需要讀。(這是asp.net 1.0的一個不足之處。)然而,該方法并沒有告訴我們有效的行的數量。同樣,也沒有方法或技巧使我們提前知道已經返回了多少結果集。
在oracle數據庫編程中,一個查詢或一個存儲過程返回的多個結果集是通過多個ref cursor對象處理的。有多少結果集,你就必須將多少輸出參數同命令關聯起來,以便nextresult方法可以用于oracle數據庫。在命令文本中,一個ado.net結果集同一個oracle ref cursor是一致的。輸出參數名必須與指針名匹配,它們的類型必須是oracletype.cursor。例如,如果要運行的存儲過程(或命令文本)引用了兩個指針(employees和orders),那么下面的代碼就說明了如何進行設置以返回兩個結果集:dim p1 as oracleparameter
p1 = cmd.parameters.add("employees", oracletype.cursor)
p1.direction = parameterdirection.output
dim p2 as oracleparameter
p2 = cmd.parameters.add("orders", oracletype.cursor)
p2.direction = parameterdirection.output
在上面的代碼中,cmd是一個oraclecommand對象,它指向一個命令或一個存儲過程。它執行代碼,創建了兩個ref cursor,稱為employees和orders。ref cursor的名稱和ado.net輸出參數的名稱必須匹配。
ado.net對象模式包含兩個主要的部分——托管提供者和database-agnostic的容器類,如dataset。托管提供者是數據源連接器的新類型;它們代替了基于com的ole db提供者。到我寫這篇文章時為止,只有少數幾個托管提供者來連接商業dbms。.net framework 1.1版只包含幾個本地提供者——用于sql server、oracle和所有ole db的提供者和odbc驅動程序。第三方的供應商也支持mysql并為oracle提供了可供選擇的提供者。
ado.net看起來類似于ado,而且托管提供者在結構上同ole db提供者也是可以相比的。除了這些相似點外,在ado.net中進行有效的編程還需要一套新的技巧和好的方法。在大多數情況下,你可以通過編寫代碼得到很多技巧,并積累對象模式方面的經驗。當你在進一步研究ado.net編程時,記住我在本文中所講的這10個ado.net技巧吧。
關于作者:
dino esposito是wintellect(www.wintellect.com)的培訓講師和顧問,他主要負責ado.net和xml課程。他是building web solutions with asp.net and ado.net和applied xml programming for microsoft.net(microsoft press)的作者,也是www.vb2themax.com的協辦人。他的聯系方式是[email protected]。