国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

掌握ADO.NET的十個熱門技巧

2024-07-10 13:02:41
字體:
來源:轉載
供稿:網友

ado.net提供了一個統一的編程模式和一組公用的類來進行任何類型的數據訪問,而不管你用何種語言來開發代碼。ado.net是全新的,但又與ado盡可能保持一致,它使編程模式從一個客戶端/服務器、基于連接的模式轉變到了一個新的模式,這個新模式可以讓斷開的前端下載記錄、離線工作、然后重新連接來提交變化。ado.net是winforms應用程序、asp.net應用程序和web services的一個共有的特點。其功能可以跨lan和internet連接來實現,可以在有狀態(stateful)和無狀態(stateless)情況下實現。

這就意味著,作為一個共有的技術,ado.net的對象在所有可能的環境中并不是同等強大的。用ado.net為一個富客戶端(rich client)構建一個數據層同為一個客戶端通常是共享的和重要的實體(如web服務器)的web應用程序構建一個數據層并不一樣。

如果你從前是個ado開發人員,現在已經用ado.net了,那么你可能把數據訪問看做是一個萬能的對象,如recordset。我們很自然地會將舊的對象模式同新的對象模式匹配起來,并將現有的方法用于.net應用程序。然而,在ado環境中的某些好的方法在轉換到ado.net環境時就可能并不強大了。而且,看起來很微不足道的ado.net對象模式的復雜性可能會導致很糟糕的編程情況、不理想的代碼、甚至是功能不能實現。我將講述在ado.net編程中可能會給你帶來麻煩的10個方面,并提供技巧和解決方法來避免它們。

1. 避免database-agnostic形式的編程
ado.net中的數據訪問是強類型的,就是說在任何時候你都必須了解你正在處理的是什么數據源(data source)。相反,在ado中,你可以編寫數據訪問代碼(它們充分利用了ole db提供者的通用模式),并將基本的數據源只看做是個參數。ado對象模式提供了唯一的連接和命令對象,它們隱藏了基本的dbms的特征。一旦你在connection對象上設置了provider屬性,那么為sql server或oracle創建一個命令對象就需要同樣的代碼。許多開發人員都通過該功能來使用生產環境外的access數據庫,以便很快地測試或演示應用程序。

在ado.net中是不能這么做的,因為在ado.net中,至少連接對象必須是特定于數據源的。你不能以一種間接或通用的方式來創建連接,除非你決定運用ado的數據訪問技術——ole db。在ado.net中,你可以用oledbconnection類創建到一個數據庫的連接,這個類可以讓你訪問各種數據源。在.net托管環境中運用system.data.oledb名字空間中的類并不特別有效,因為它們是用ole db來訪問數據的。你只能用ole db來訪問那些沒有.net數據提供者的數據源。

如果你的應用程序必須訪問全異的數據源(而且你知道可能涉及什么數據源——一個合理的假設),那么你可以創建一個集中的factory類,它返回一個連接對象,并通過一個通用的接口(idbconnection接口)來管理這個連接對象。factory類在內部運用應用程序參數來決定使用什么.net數據提供者:' create the connection
dim factory as new myappconnectionfactory
dim conn as idbconnection
conn = factory.createconnection(connstring)

' create the command
dim cmd as idbcommand = conn.createcommand(query)




一旦你得到了一個連接對象,你就可以以database-agnostic的方式來創建和執行一個命令了,而不管使用的數據源是什么。你可以使用createcommand方法并通過idbcommand接口來引用命令。然后,你可以用idbcommand接口上的executereader方法或executenonquery方法來執行命令。如果你用executereader,你就可以得到一個data reader并可以用idatareader接口來對它進行一般的訪問了。

你不能用一個通用的數據庫編程模式來填充一個dataset對象。實際上,你不能像創建一個命令那樣以一種間接的方式來創建data adapter對象。原因就是,在有些情況下,data adapter不同于命令對象,它可以在內部隱含地創建一個連接。然而,它必須以一種強類型的方式工作,而且必須知道基本的數據庫服務器是什么。

2. 運用字符串來串行化擴展的屬性
幾個ado.net對象都擁有一個叫做extendedproperties的集合。該屬性就像收集貨物(cargo collection)一樣,可以用來存儲任何類型的用戶信息。dataset、datatable和datacolumn就是可以提供該數據成員的類。ado.net通過運用propertycollection類封裝的一個哈希表來實現這個extendedproperties屬性。你可以用add方法將數據插入到集合中。add方法使用了兩個參數來保存數據——key和value。該方法的原形將參數定義為通用的對象類型,你可以存儲任何類型的信息。然而,在特殊情況下,你應該特別注意那些被保存為擴展屬性的對象的類型。

如果你想將包含擴展屬性的ado.net對象串行化到xml,最好只用字符串。如果不行,你必須對ado.net的內在的serializer的行為采取對策。

當ado.net將一個dataset對象保存到xml時,extendedproperties集合的內容就被串行化到內存中了,但大概是出于性能的原因,ado.net運用了tostring方法,而不是xml serializer來實現串行化。更重要的是,當ado.net對象被讀回并復原時,extendedproperties集合包含的是對象的字符串表現形式,而不是對象本身。

3. 運用具有blob字段的executexmlreader
用于sql server的.net數據提供者(data provider)使用了數據庫提供的xml擴展名,并提供了一個額外的方法(executexmlreader)來執行查詢。命令對象上的所有的執行者(例如executereader和executescaler)都采用不同的方法來得到結果集。excecutereader通過一個托管指針(managed cursor)(data reader)來返回數據,而executescaler返回結果集中的第一個值,把它作為一個標量值。executexmlreader執行查詢,并返回已經綁定到一個xmltextreader對象的基于xml的輸出流。通過這種方式,你就不需要做額外的工作來以xml的方式加工數據了。要實現這一點,查詢字符串必須返回xml數據。對sql server來說,當查詢字符串包含一個for xml子句時,就可以實現它。盡管這只是一種可能。

一個不太為人所知的情況是,要使executexmlreader工作,讓結果集包含xml數據就足夠了。 下面的查詢方法很好,只要列包含xml格式的文本就行:select data from table where key=1

這個列是個典型的blob或ntext字段,其文本顯示為xml。簡要地看看executexmlreader方法的內部結構會有助于我們的理解。該方法用executereader來執行查詢,并從數據提供者得到一個數據流對象。接下來,它將數據流綁定到xmltextreader類的一個新創建的實例上,這個實例被返回給調用者。連接一直處于忙碌狀態,直到xml reader停止工作。sql server提供者是唯一的提供者,它提供了方法讓我們從一個xml reader直接讀取數據,但這種做法更多的是與提供者有關,而與數據庫性能的關系并不大。oracle支持xml查詢,但oracle的數據提供者并不支持xml查詢。相比之下,為ole db數據提供者編寫一個executexmlreader方法并不難(點此下載實例)。

4. 不要設法緩存一個dataview
dataset和datatable對象是唯一的包含數據的ado.net對象。dataview是一個不能串行化的、輕量級的類,它只代表構建在一個表上的視圖(view)。你可以根據一個表達式或行的狀態來過濾視圖。許多應用程序都需要你管理數據視圖并將它們綁定到數據控件上,如windows和web datagrid控件。一個dataview對象不能緩存數據;它只是緩存了與當前過濾器相匹配的基本的表中的行的索引。緩存索引的順序與當前的排序表達式一致。緩存dataview而不緩存基本的datatable是不行的。

例如,提供分頁(比如通過運用datagrid控件)的asp.net應用程序通常以一個dataview對象結尾,因為它支持排序和過濾。在有些情況下(大多是基于性能的原因),你可能決定要緩存數據源。要緩存的對象不能是dataview(它是你實際綁定的對象)。一個dataview只是一種索引,如果沒有基本的datatable對象,它是沒有用的。

5. 運用find來讀取一個記錄
通過運用datatable的select方法來運行一個內存中的查詢,或在視圖上設置一個過濾器來濾掉與指定標準不匹配的所有的記錄,你就可以讀取一個datatable對象中的一個特定的行了。你可以通過設置dataview類上的rowfilter屬性來設置一個過濾器。這兩種方法都運用相同的引擎來選擇記錄。它們可以接納一個表達式,對它進行解析并求各個子句的值。datatable的select方法返回一個帶有所有相匹配的datarow對象的數組。rowfilter屬性重建dataview的內部索引來包含所有的(且僅包含)匹配的記錄。然后,應用程序就可以訪問記錄了。這兩種方法在性能上幾乎是一樣的;運用哪種方法取決于環境和個人喜好。例如,如果你用的是數據綁定的控件,如一個datagrid或datalist,那么rowfilter就很理想。如果你必須處理一串記錄,那么select方法就更好了。

然而,你還可以用另一種方法(仍然是基于dataview的),它是讀取一個表中的記錄的最快的方法。該方法就是用find:dim view as dataview
view = new dataview(table)
view.sort = "orderid"
dim index as integer = view.find(10248)
dim row as datarow = view(index).row




find方法運用了視圖的當前索引,并將指定的值(或多個值)與形成當前索引的字段匹配起來。在前面的代碼中,值10248與列orderid匹配。如果sort屬性為空,且datatable對象有一個主鍵,那么就運用主鍵中的列。find方法返回的是相匹配的第一行的基于0的位置的值。

如果你想返回多個記錄,可以用findrows的演變形式: view.sort = "orderid, discount"
dim keys(1) as object
keys(0) = 10248
keys(1) = 0
dim row as datarow = _
view(view.find(keys)).row




前面的代碼可以讓你通過運用find的重載方法(帶有一組對象)來匹配多個列的值。

6. 盡可能用預先排序的數據
ado.net對象模式使我們可以很容易地實現排序。你可以創建一個dataview對象并設置其sort屬性;ado.net runtime查看新的排序表達式并為視圖重編索引。該步驟是在內存中實現的,但速度并不快。排序的花費很高,更重要的是,它并不是個線性操作(linear operation)。對一組數據進行排序需要n*log(n)的計算成本,就是說,隨著需要排序的條目數量的增加,直線增加的成本是很大的。因此,你應該限制應用程序中的排序,盡可能地運用預先排序的數據。在web應用程序中,動態排序對性能的影響是相當大的。既然如此,你就應該設計應用程序,限制對動態排序的需求,并依賴在數據庫服務器中寫死的算法。除非你在用應用程序的一個可以使復雜性低于n*log(n)極限的特殊的功能,否則避免運用手工排序算法,因為這種算法可能比系統中的算法更糟。

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)中,你應該可以得到非常緊湊的輸出結果。雖然你得到的結果文件是最小的,但遺憾的是,它實際上并不小?;闹嚨氖牵惚4娴揭粋€二進制的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類的所有成員映射到數組和值成員中。

運用一個派生的類和一個自定義的串行化方案可以為一個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技巧吧。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 神木县| 微山县| 台湾省| 深圳市| 瑞金市| 杭锦旗| 阿巴嘎旗| 恩平市| 方山县| 黄石市| 信丰县| 万载县| 东台市| 垦利县| 纳雍县| 清远市| 富阳市| 七台河市| 仁怀市| 北宁市| 汉中市| 获嘉县| 克东县| 石景山区| 禄丰县| 库尔勒市| 灌云县| 临江市| 铜鼓县| 满城县| 诸城市| 多伦县| 昌平区| 姚安县| 虹口区| 嵊州市| 陵水| 治县。| 福鼎市| 乐至县| 玉树县|