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