t.與xml結合
ado.net在dataset中提供對xml的廣泛支持,同時在sql server2000或以后版本中的xml功能性擴展也能在ado.net中得到充分運用。你可以使用sqlxml訪問在sql server2000和以后版本中提供的xml功能性擴展。下面是使用xml和ado.net的一些技巧信息。
i.dataset和xml
dataset和xml的完美整合,可以使你完成以下事情:
①從xsd計劃中載入一個dataset的計劃或相關結構;
下面的例子說明一個xsd文件的結構,其中mydataset就是我們的dataset元素,它下面包含一個customers復合類型元素,有了它我們就可以映射創建一個這樣的表:customers (customerid,companyname,phone),同時也定義我們的dataset的計劃或者結構:
<xs:schema id="someid"
xmlns=""
xmlns:xs="http://www.w3.org/2001/xmlschema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="mydataset" msdata:isdataset="true">
<xs:complextype>
<xs:choice maxoccurs="unbounded">
<xs:element name="customers" >
<xs:complextype >
<xs:sequence>
<xs:element name="customerid" type="xs:integer"
minoccurs="0" />
<xs:element name="companyname" type="xs:string"
minoccurs="0" />
<xs:element name="phone" type="xs:string" />
</xs:sequence>
</xs:complextype>
</xs:element>
</xs:choice>
</xs:complextype>
</xs:element>
</xs:schema>
②從xml文件中載入一個dataset的內容;
要從xml文件填充dataset的內容,請使用dataset對象的readxml方法。下面的例子說明如何從一個xml文件讀取數據到一個dataset:
‘visual basic
dim myds as dataset = new dataset
myds.readxml("input.xml", xmlreadmode.readschema)
‘c#
dataset myds = new dataset();
myds.readxml("input.xml", xmlreadmode.readschema);
③當沒有提供計劃時從一個xml文件的內容中推斷一個dataset的計劃;
要從一個xml文件載入dataset的計劃信息,你可以使用dataset對象的readxmlschema方法。如果沒有提供計劃,你還可以使用inferxmlschema從xml文件推斷dataset的計劃,下面的例子介紹如何通過inferxmlschema從一個xml文件推斷出dataset的計劃:
‘visual basic
dim myds as dataset = new dataset
myds.inferxmlschema("input_od.xml", new string[] {"urn:schemas-microsoft-com:officedata"})
‘c#
dataset myds = new dataset();
myds.inferxmlschema("input_od.xml", new string[] "urn:schemas-microsoft-com:officedata");
④象xsd格式計劃一樣寫一個dataset的計劃;
下面的例子展示如何通過readxmlschema從一個xsd文件載入dataset的計劃:
‘visual basic
dim myds as dataset = new dataset
myds.readxmlschema("schema.xsd")
‘c#
dataset myds = new dataset();
myds.readxmlschema("schema.xsd");
⑤象xml格式文件一樣讀寫一個dataset的內容。
利用diffgrams從dataset中讀寫內容,下面的例子顯示在提交更改之前更新表中一行數據的結果,其中customerid為alfki的那一行數據被修改但是還沒有更新:
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<customerdataset>
<customers diffgr:id="customers1" msdata:roworder="0" diffgr:haschanges="modified">
<customerid>alfki</customerid>
<companyname>new company</companyname>
</customers>
<customers diffgr:id="customers2" msdata:roworder="1" diffgram:haserrors="true">
<customerid>anatr</customerid>
<companyname>ana trujillo emparedados y helados</companyname>
</customers>
<customers diffgr:id="customers3" msdata:roworder="2">
<customerid>anton</customerid>
<companyname>antonio moreno taquería</companyname>
</customers>
<customers diffgr:id="customers4" msdata:roworder="3">
<customerid>arout</customerid>
<companyname>around the horn</companyname>
</customers>
</customerdataset>
<diffgr:before>
<customers diffgr:id="customers1" msdata:roworder="0">
<customerid>alfki</customerid>
<companyname>alfreds futterkiste</companyname>
</customers>
</diffgr:before>
<diffgr:errors>
<customers diffgr:id="customers2" diffgr:error="an optimistic concurrency violation has occurred for this row."/>
</diffgr:errors>
</diffgr:diffgram>
注意:你可以在你的dataset中使用xpath查詢和xslt轉換來同步運用xml的功能性,或者提供一個相關的視圖,或者創建一個xml文檔數據的一個副本。
ii.計劃接口
當你從一個xml文件載入一個dataset時,你可以從xsd計劃載入dataset的計劃,或者你可以在載入數據之前預先確定表和列。如果這里沒有xsd計劃或者你又不知道那個表和列是xml文件內容確定的,那么你可以使用基于xml文檔結構推斷計劃。
計劃接口是一個很有用的移植工具,但是它應該限制在設計階段的應用程序中,僅僅因為以下幾點:
①推斷計劃將會提出額外的處理從而影響應用程序性能的提高;
②所有的列將會是一個數據類型:string;
③推斷過程具有不確定性。那就是說,它是基于xml文件的,而不是基于有意的計劃。
iii.sql server 的for xml查詢
如果你想返回如sql server的for xml查詢結果,你可以用sql server.net data provider直接使用sqlcommand.executexmlreader方法創建一個xmlreader。
iv.sqlxml管理類
在.net框架中sqlxml管理類使用microsoft.data.sqlxml命名空間。它使得你可以執行xpath查詢和xml模板文件,如同運用xslt轉換數據一樣。最新版本是sqlxml3.0。
u.更多有用技巧
i.避免自動增量值沖突
像大多數數據庫一樣,dataset讓你在增加新的數據時標識為自動增量的列自動填充增量值。使用自動增量時,應當避免本地dataset的增量值與數據庫的增量值相沖突。要避免這種情況,推薦在數據庫和dataset同時使用自動增量時,在你的dataset中創建autoincrementstep為-1和autoincrementseed為0的自動增量列,同時保證你的數據庫中的列從1開始正方向遞增。這樣就保證一個負方向的增量不會與一個正方向的增量相沖突。另外一種方法是使用guid代替自動增量。在dataset中產生的guid永遠不會與數據庫中產生的guid一樣。如果你的自動增量列只是簡單地用作唯一值,并且不表示任何含義,建議你使用guids代替自動增量。它們是唯一的并避免使用自動增量產生的額外工作。
ii.處理樂觀并發錯誤
因為dataset與數據庫是分離的,所以你應該在你的應用程序中避免當多個客戶更新數據庫數據時發生沖突。這里有幾種處理樂觀并發錯誤的解決方案。一是在你的表中增加一個時間戳列。二是校驗一行中所有列的數據是否與你在sql聲明中使用where子句找到的數據靜態匹配。下面的例子說明如何使用where條件處理樂觀并發錯誤:
‘visual basic
dim nwindconn as sqlconnection = new sqlconnection("data source=localhost;integrated security=sspi;initial catalog=northwind")
dim custda as sqldataadapter = new sqldataadapter("select customerid, companyname from customers order by customerid", nwindconn)
' the update command checks for optimistic concurrency violations in the where clause.
custda.updatecommand = new sqlcommand("update customers (customerid, companyname) values(@customerid, @companyname) " & _
"where customerid = @oldcustomerid and companyname = @oldcompanyname", nwindconn)
custda.updatecommand.parameters.add("@customerid", sqldbtype.nchar, 5, "customerid")
custda.updatecommand.parameters.add("@companyname", sqldbtype.nvarchar, 30, "companyname")
' pass the original values to the where clause parameters.
dim myparm as sqlparameter
myparm = custda.updatecommand.parameters.add("@oldcustomerid", sqldbtype.nchar, 5, "customerid")
myparm.sourceversion = datarowversion.original
myparm = custda.updatecommand.parameters.add("@oldcompanyname", sqldbtype.nvarchar, 30, "companyname")
myparm.sourceversion = datarowversion.original
' add the rowupdated event handler.
addhandler custda.rowupdated, new sqlrowupdatedeventhandler(addressof onrowupdated)
dim custds as dataset = new dataset()
custda.fill(custds, "customers")
' modify the dataset contents.
custda.update(custds, "customers")
dim myrow as datarow
for each myrow in custds.tables("customers").rows
if myrow.haserrors then console.writeline(myrow(0) & vbcrlf & myrow.rowerror)
next
private shared sub onrowupdated(sender as object, args as sqlrowupdatedeventargs)
if args.recordsaffected = 0
args.row.rowerror = "optimistic concurrency violation encountered"
args.status = updatestatus.skipcurrentrow
end if
end sub
‘c#
sqlconnection nwindconn = new sqlconnection("data source=localhost;integrated security=sspi;initial catalog=northwind");
sqldataadapter custda = new sqldataadapter("select customerid, companyname from customers order by customerid", nwindconn);
// the update command checks for optimistic concurrency violations in the where clause.
custda.updatecommand = new sqlcommand("update customers (customerid, companyname) values(@customerid, @companyname) " +
"where customerid = @oldcustomerid and companyname = @oldcompanyname", nwindconn);
custda.updatecommand.parameters.add("@customerid", sqldbtype.nchar, 5, "customerid");
custda.updatecommand.parameters.add("@companyname", sqldbtype.nvarchar, 30, "companyname");
// pass the original values to the where clause parameters.
sqlparameter myparm;
myparm = custda.updatecommand.parameters.add("@oldcustomerid", sqldbtype.nchar, 5, "customerid");
myparm.sourceversion = datarowversion.original;
myparm = custda.updatecommand.parameters.add("@oldcompanyname", sqldbtype.nvarchar, 30, "companyname");
myparm.sourceversion = datarowversion.original;
// add the rowupdated event handler.
custda.rowupdated += new sqlrowupdatedeventhandler(onrowupdated);
dataset custds = new dataset();
custda.fill(custds, "customers");
// modify the dataset contents.
custda.update(custds, "customers");
foreach (datarow myrow in custds.tables["customers"].rows)
{
if (myrow.haserrors)
console.writeline(myrow[0] + "/n" + myrow.rowerror);
}
protected static void onrowupdated(object sender, sqlrowupdatedeventargs args)
{
if (args.recordsaffected == 0)
{
args.row.rowerror = "optimistic concurrency violation encountered";
args.status = updatestatus.skipcurrentrow;
}
}
iii.協作設計
在你寫期間,你應當鎖定dataset。
iv.僅當需要的時候才使用com對象訪問ado
ado.net設計為大量應用程序最好的解決方案。然而一些應用程序需要只有ado對象才能提供的功能,比如adomd。這種情況下可以使用com對象訪問ado,注意的是使用com對象訪問ado數據會影響應用程序的執行效率。所以在設計應用程序時,首先應該考慮在使用com對象訪問ado數據之前,看看ado.net是否就滿足你的設計要求。
v.ado.net和ado的比較
i.ado.net在ado設計模型的基礎上演變和發展而來,它并不取代com程序員的ado,更多地,它是為.net程序員訪問相關數據源、xml和應用程序數據設計。ado.net支持多樣化的發展要求,包括創建數據庫客戶端和供應用程序、工具、語言、web瀏覽器等使用的中間層業務對象。ado.net與ado有許多相似的地方。
ii.ado為com程序員提供了高效的、強大的與數據庫打交道的各種接口。ado能得到廣泛的運用是因為它支持任何的自動化控制語言(比如vc、vb和腳本語言等)的調用。ado基礎上升級而來的ado.net提供更好的交互平臺和可升級的數據訪問。在ado.net中創建一個新的數據訪問api集能提供較之于ado接口幾個優越的地方,如下所述:
①改進了與xml的結合
隨著xml在應用程序中扮演著越來越重要的角色,與xml結合的ado.net就應運而生。為了持續和裝載數據以及數據的xml格式,ado.net依賴xml在多層之間或客戶機之間遠程傳遞數據。ado.net中使用的特殊xml表述形式提供在任何網絡中十分便利地傳輸數據的方法,包括數據安全邊界。同時,ado.net使用xml工具執行確認、分級查詢和數據和數據之間的轉換。
②綜合.net框架
ado結構如recordset并不使用常見的設計結構,相反它模擬成一種數據導向。舉例,ado中的用來導航和得到數據的游標,它的功能性就與其它的比如數組和集合數據結構不同。然而,在ado.net中,因為存儲的數據能通過公共的.net框架結構暴露,包括數組和集合,所以你可以使用一些公共的方法與你的相關數據打交道。
③改良對離散業務模型的支持
ado使用recordset提供有限的對離散訪問的支持。ado.net介紹一個新的對象dataset,它作為相關數據的一個公共的、存儲的表現形式,在任何時候都被設計為離散的,它與外部數據并不保持持久的連接,它是包裝、存儲、交換、延續和裝載數據的好方法。也就是說任何對數據的操作都是在本地進行,而不直接與真實的數據庫打交道。
④數據訪問行為的控制是清楚的
ado中包括在應用程序中并不總是要求和指定的隱含行為會限制應用程序的性能。而在ado.net中提供良好的定義和預先的行為、執行和語義要素組件使得你可以在一個高優化的方式下定位到一個普通的情節上。
⑤改善設計階段的支持
ado源自執行階段隱含的數據信息,而這種信息是基于花費昂貴代價才獲得的元數據。在ado.net中的元數據只是在設計階段起一個杠桿作用,從而提供執行階段更好的性能和更好的穩定性。
iii.ado設計
為了更好地理解ado.net模型和設計思想,回顧一下ado的概念是有用的。ado使用一個單一的對象recordset與所有數據類型打交道。recordset被用來處理從數據庫返回的只進流數據、翻卷服務器上數據或者翻卷一批存儲結果集。數據上的改變會立即運用到數據庫上或運用到使用樂觀查詢和更新操作的一批數據上。當你創建一個recordset時你就明確了你所作的任務,recordset結果行為的改變主要取決于你要求的recordset參數。因為ado使用一個單一的能在很多場合使用的recordset對象,這使得你的應用程序中的對象模型很簡單。然而,也很難寫一個公用的、可預言的和最優化的代碼,那是因為行為、執行和一個單一對象描述的語義要得到改變很大程度上取決于對象是如何創建和對象訪問的是什么數據。
iv.ado.net設計
ado.net是考慮到開發者在訪問和使用數據時共同面對的任務和問題而設計。寧可使用一個單一對象執行大量任務,還不如如ado.net中指定每個對象的功能性因素去完成對應的每個任務。ado中的recordset功能性被分解成ado.net中以下的幾個清楚對象:datareader,提供快速的、只進的和只讀的訪問去查詢結果;dataset,存儲數據;dataadapter,在dataset和數據源之間架起一道橋梁;executenonquery,不返回行;executescalar,返回一個單一值而不是一個行集。下面是一些詳細說明:
①只進、只讀數據流
應用程序,特別是中間層應用程序,經常要程序化地處理一系列結果,要求在他們讀的時候沒有用戶交互和沒有更新或回滾結果。在ado中,執行這類數據時使用recordset的只進游標和只讀鎖。在ado.net中,datareader優化了這種數據的執行性能,它通過提供一個非緩沖、只進和只讀的數據流從數據庫得到數據。
②返回單一值
在ado中要得到一個單一值,你需要通過創建一個recordset—〉讀取結果—〉得到單一值—〉關閉recordset這樣一個過程。在ado.net中你就可以使用command對象的executescalar方法不需要額外的操作來獲得單一值。
③離散數據訪問
ado使用客戶端游標定位離散數據的訪問,而在ado.net中dataset可以很清楚地實現離散數據的訪問。dataset能從一個多樣的不同的數據源提供一個公有的、完全離散的數據表現形式,是因為dataset是完全獨立于數據源的。它不管你數據是從數據庫來的,還是從xml文件來的,抑或是從應用程序中得到的。一個簡單的dataset可以裝載從多個不同數據庫或非數據庫源的數據。然后使用datarelation在多個表之間建立一個連接,盡管recordset的msdatashape提供者可以實現分級結構查詢,但是dataset提供更高的穩定性處理離散數據。同時dataset提供以xml文件格式在遠程客戶端和服務器之間傳輸數據。
④從數據庫得到數據和更新數據
ado.net提供更好的執行階段性能和可見性。舉例,當使用ado的recordset對象進行批更新時,你必須為每個需要改變結果的行使用update、insert或delete聲明。ado產生這些聲明,在執行階段,是需要付出昂貴代價的獲得元數據的。而在ado.net中,指定update、insert或delete命令就如同自定義業務邏輯(比如一個存儲過程)一樣,你可以使用dataadapter實現這一切。dataadapter在dataset和數據源之間架起一道橋梁。讓你在執行階段就不是如ado的recordset一樣需要在數據源中收集元數據信息。從而改善應用程序的執行性能。
v.數據類型
在ado中,所有的結果返回一個variant數據類型,在ado.net中,你可以得到列本身的數據類型。數據類型可以在system.data.sqltypes名稱空間定義。
w.有關ado和ado.net的詳細介紹,請參考微軟上的資料:ado.net for the ado programmer
總結:
通過本文,希望與大家共同交流和學習,有不當之處請大家指正,謝謝!
ado.net最佳實踐(上)
http://www.csdn.net/develop/read_article.asp?id=22662