﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-kapok-随笔分类-.NET</title><link>http://www2.blogjava.net/kapok/category/803.html</link><description>垃圾桶,嘿嘿，我藏的这么深你们还能找到啊，真牛！</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 03:20:21 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 03:20:21 GMT</pubDate><ttl>60</ttl><item><title>简化.NET assembly类库 </title><link>http://www.blogjava.net/kapok/archive/2005/04/17/3385.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Sun, 17 Apr 2005 10:35:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/04/17/3385.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/3385.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/04/17/3385.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/3385.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/3385.html</trackback:ping><description><![CDATA[<TABLE cellSpacing=0 cellPadding=4 width="95%" border=0>
<P>
<TBODY>
<TR>
<TD class=textblack><B>简化.NET assembly类库</B> </TD></TR>
<TR>
<TD class=textblack>作者： <FONT color=#880000>silicon.com</FONT> <BR>2005-03-16 12:7 PM</TD></TR>
<TR>
<TD class=textgray>
<P>
<P>维护头文件通常是一个冗长乏味并且容易出错的过程，感谢.NET &nbsp;assembly类库抹去了对这些文件的倚赖。</P>
<P>微软.NET的可管理的C++最终简化了我们创建类库的方法，或更准确些，.NET assembly类库，这种简化得以实现主要是由于assembly类库是可以自我描述的。这对一个Managed C++程序员意味着什么呢？基本上讲，一旦 assembly编译成功，你在编译传统C++类库的时谨慎创建的所有头文件除了维护的需要外，都不再是必需的。</P>
<TABLE cellSpacing=0 cellPadding=0 width=0 align=right border=0>
<TBODY>
<TR>
<TD align=middle><IMG src="http://www.zdnet.com.cn/ads/image/advertisement_e1.gif"></TD></TR>
<TR>
<TD><!--start banner ad--><!--ba-->
<SCRIPT language=JavaScript1.1 src="http://ad.cn.doubleclick.net/adj/messagingplus.zdnet.com.cn/developer/code;sz=1x1;ord=265712958?"> </SCRIPT>
<NOSCRIPT> <A HREF="http://ad.cn.doubleclick.net/jump/messagingplus.zdnet.com.cn/developer/code;sz=1x1;ord=265712958?"> <IMG SRC="http://ad.cn.doubleclick.net/ad/messagingplus.zdnet.com.cn/developer/code;sz=1x1;ord=265712958?" border=0 ></A> 
      </NOSCRIPT><!--end banner ad--></TD></TR></TBODY></TABLE>
<P>就个人而言，我感觉维护头文件是一种痛苦，所以我很高兴看到这种对头文件的倚赖正在消失。我经常会忘记需要在库中引用的一个或多个头文件的名称，为了找到缺失的数据类型定义，我不得不对所有含有头文件的内容进行搜索，更糟糕的是，将源代码拆分为两半增加了我犯错误的机会。我经常犯的错误包括忘记将所有的包含头文件打包、使.h文件和.cpp脱离同步。</P>
<P>既然对头文件的程序集不再是必需的，你可以使用一种改进了的新方法来创建源文件。但在考察这种方法之前，先让我们先来回顾一下创建程序集的传统方法</P>
<P>&nbsp;</P>
<P><B>传统方法</B></P>
<P>在C++中，传统的库文件创建方法是建立一系列头文件用以描述类库中所有的功能；接下来，你要在一个单独的源文件中实现这些头文件所定义了的所有功能。然后，在编译器中运行每一个源代码文件连同其相关的头文件，以生成目标文件；再将所有的目标文件相互链接来创建库文件</P>
<P>图A描述了这种传统方法。</P><IMG height=577 src="http://www.zdnet.com.cn/i/developer/story/200501/10/image001.gif" width=434> 
<P>图A&nbsp; </P>
<P>创建库的传统方法</P>
<P>使用头文件的原因在于，今后引用这个类的时候，所有的类、结构体、变量等等都可以很方便的定义。</P>
<P>程序集可以使用同样的方法生成，这一过程的唯一区别在于Managed C++的标志是事先确定的。</P>
<P>在下面的例子中，列表A、B、C和D演示了如何用传统C++的方法创建一个 assembly。</P>
<P>列表A给出了头文件Cards.h的定义，这个文件定义了一个包含扑克牌和Card类的枚举(enmu)，注意，使用ManagedC++时，关键字public要放在enum和class之前的，因为这两者都需要在全局范围内可以被访问。</P>
<P>列表B展示了类的构造器和成员方法的实现，列表C定义了第二个类Deck，注意，虽然从来没有在头文件中定义，但Card类是在Deck类之内使用的，使用这一技巧需要谨记：在编译过程中，头文件基本上是大批量地粘贴到源文件中的。既然是这样的情况，我们只需简单地在Deck.cpp源文件的包含文件列表中将Card.h放在Deck.h的前面，如此操作之后，Card类将首先被粘贴，继而被定义为Deck类所必需的类。</P>
<P>&nbsp;</P>
<P>列表D显示了在这个迷你库中的源文件，注意，正如我们刚刚所提到的，Card.h包含在Deck.h之前。</P>
<P>&nbsp;</P>
<P>在命令行中执行建立 assembly库的命令并不像火箭科学一样艰难，其语法（没有这些省略号）非常简单：</P>
<P>cl source1.cpp source2.cpp ... sourceN.cpp /CLR /LD /o OutputName.dll</P>
<P>&nbsp;</P>
<P>C++编译器取走这一系列源文件的名称，然后是/CLR参数，它告诉编译器我们正在使用managed的扩展，继而/LD参数告诉连接器去创建一个.dll文件，最后/o参数将说明这个.dll文件的名称。</P>
<P>&nbsp;</P>
<P>为了编译以上的例子，你可能会用到这行命令：</P>
<P>clcard.cppdeck.cpp /CLR /LD /o cards.dll </P>
<P>&nbsp;</P>
<P><B>新的 assembly方法</B></P>
<P>不再受困于分离头文件和源文件的工作，就为新的库文件编码方式提供了可能性。在兜了一个圈子之后，我将开始介绍我的简便方法，首先，将所有的类以类文件(.h)形式进行编码，其中包括所有的定义和实现；然后使用一个单独的连接器文件(.cpp)来包含所有的类文件；这种方法唯一有些棘手的部分在于，你要确定所有的类文件是按照正确的顺序排列的，以保证一切需要调用的数据类型在使用之前都已经定义好了，即使使用传统方法，这一问题同样需要处理。图B展示了这种新的 assembly方法。</P><IMG src="http://www.zdnet.com.cn/i/developer/story/200501/10/image002.gif"> 
<P>图B</P>
<P>新的 assembly方法</P>
<P>&nbsp;</P>
<P>采用这种方法，你只需维护半数文件，既然定义和源码是一同定义的，就不会造成不同步的。这样一来，维护库的工作就简单了很多，另外，开发文档只需保存在一个地方，也就更容易阅读，所有这些都说说明了这是一种更好的方法。</P>
<P>&nbsp;</P>
<P>列表E、F和G展示了使用新方法生成的同样的库。</P>
<P>&nbsp;</P>
<P>正如你看到的那样，列表E是传统方法中Card.h和Card.cpp这两个文件相结合而形成的，我基本上只是把实现部分直接放在类的定义中，而不是在一个单独的文件中进行定义。</P>
<P>&nbsp;</P>
<P>同样的，列表F是传统方法中Deck.h和Deck.cpp这两个文件相结合形成的，如果使用传统方法，你可以在这个类中访问其他的类而不必在文件中定义他们，连接器文件需要确保所有类的定义是按照正确的顺序排列的，以保证这些类在使用之前都已经定义好了。</P>
<P>&nbsp;</P>
<P>在列表G中显示的连接器文件是唯一一个与众不同的文件，它除了包含语句之外没有任何其他的东西，ManagedC++编译器只编译.cpp文件，为了让编译器完成所有的工作，你必须有这个文件。这种便利所带来的副作用是从库中添加或删除类变得容易了，而你已经将组成库的类名称记录在了一个单一的地方。在开发过程中，连接器文件还是一个放置测试代码的理想场所。</P>
<P>&nbsp;</P>
<P>以这种方法建立一个assembly类库的额外的优点是，在命令行条件下使用时，其命令很简单：</P>
<P>clcards.cpp /CLR /LD </P>
<P>&nbsp;</P>
<P><B>结论</B></P>
<P>具有自我描述功能的 assembly器简化了我们编码的方法，这主要是因为源代码模块不再需要被分离为头文件和源码文件，正因为得益于此，我们展示了一种构造 assembly库的新方法。</P><BR><BR>责任编辑：<A href="mailto:li_ning@zdnet.com.cn?subject=http://www.zdnet.com.cn/developer/news/story/0,3800066930,39336568,00.htm">李宁</A><BR></TD></TR></TBODY></P></TABLE><img src ="http://www.blogjava.net/kapok/aggbug/3385.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-04-17 18:35 <a href="http://www.blogjava.net/kapok/archive/2005/04/17/3385.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用ADO.NET的Connection对象 </title><link>http://www.blogjava.net/kapok/archive/2005/04/12/3177.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Tue, 12 Apr 2005 06:59:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/04/12/3177.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/3177.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/04/12/3177.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/3177.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/3177.html</trackback:ping><description><![CDATA[<A href="http://blog.csdn.net/jabby12/archive/2004/08/03/59602.aspx">http://blog.csdn.net/jabby12/archive/2004/08/03/59602.aspx</A><BR>&nbsp;&nbsp;在ADO.NET对象模型中，Connection对象代表了与数据源之间的连接。.NET框架中有两个Connection对象：一个是OleDbConnection,用于大多数的数据库连接，一个是SqlConnection，是MS开发的专门用于针对SQL Server的连接。在创建Connection对象之前，你必须先引用System.Data.OleDb或者System.Data.SqlClient和System.Data三个名空间。
<P>1.<FONT color=#ff0000>SQL Server数据库的连接</FONT>&nbsp;&nbsp;&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;你可以使用Connection对象的属性来指定数据源的位置及其它参数来连接数据库。如：SqConnection con=new SqlConnection("Provider=SQLOLEDB;Data Source=MyServer;Initial Catalog=database;use id=yourid,password=yourpassword;");</P>
<P>这是连接到本地数据库，如果你想连到网络上的的数据库，就要利用集成安全性，同时忽略用户名和密码。如：</P>
<P>SqConnection con=new SqlConnection("Provider=SQLOLEDB;Data Source=MyServer;Initial Catalog=database;Integrated Security=SSPI");</P>
<P>如果使用的是ODBC连接到SQL Server，可以通过使用Trusted_Connection＝yes;来使用网络数据库。</P>
<P><FONT color=#ff0000><FONT color=#000000>2.</FONT>Oracle数据库的连接：（前提：必须先安装Oracle客户端实用工具的适当版本，并创建数据库别名，接着就可以用以下的连接字符串进行连接）</FONT></P>
<P>SqConnection con=new SqlConnection("Provider=MSDAORA;Data Source=dbAlias;User id=yourid,password=youpwd;);</P>
<P>3.<FONT color=#ff0000>Access数据库的连接：（你可以使用以下连接字符串来连接）</FONT></P>SqConnection con=new SqlConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\yourdb.mdb;User id=yourid,password=youpwd;); 
<P>连接到数据库之后即可调用Connection对象的Open()方法来打开与数据库的连接，同理Close()方法用来关闭与数据库的连接。</P>
<P><FONT color=#0000ff>连接池：</FONT></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#000000>连接池是什么？在一个三层结构（或N层）中，当一个客户端与中间层服务器进行通讯的时候，服务器会创建一个与数据库连接，并执行操作的业务对象（也就是与数据库连接的实例），同时会创建一个</FONT><FONT color=#25437c>Connection对象，在放在一个池中（实际上是一个线程）。当释放这个实例的时候，此实例便关闭，此时并没有真正的关闭数据连接，而是将Connection对象标记为关闭后存储在池中。如果这时再来启动一个新的业务对象，这时就会检查现有的连接，如果池中有打开的连接，即使用它，否则再创建一个新连接。</FONT></P>
<P><FONT color=#25437c>可能你会觉得很奇怪，如果这样，那池中不是有很多的对象，岂不是会浪费很多的资源，这个问题的解决方案是你可以设置与数据库的特定连接时间（默认60秒），如果在这个时间内未被使用，.NET提供就会关闭此连接。</FONT></P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何打开连接池？默认情况下是打开的.</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如何关闭连接池？可以使用OleDbConnection.<FONT color=#000000>ReleaseConnectionPool</FONT>()方法来关闭连接池，更或者你可以在ＯＬＥ　ＤＢ连接字符串中加上OLE DB Services= - 4;在用SqlConnection对象时可在连接符中加上Pooling=False。这时你再调用Close()时候便会真正地关闭与数据库的连接。</P>
<P>（注1：可以使用ＳＱＬ事件探查器或性能监视器来观察连接到数据库中的连接数目，以识别连接是否真正关闭或是只是放入池中。）</P>
<P>（注2：可以显式调用Dispose()方法在垃圾收集器回收之前释放资源，但如果你只是将Connection对象设为ＮＵＬＬ的话，是不会断开与数据源的连接的）</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#0000ff>&nbsp;利用Connection对象来创建Command对象</FONT>：(ADO.NET中用Command对象来执行数据查询，更新）例　：</P>
<P>SqConnection con=new SqlConnection("Provider=SQLOLEDB;Data Source=MyServer;Initial Catalog=database;Integrated Security=SSPI");</P>
<P>using (OleDbCommand cmd=con.CreateCommadn()) </P>
<P>{</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.CommandText="select * from table";</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmd.ExecuteNonQuery();</P>
<P>}</P>
<P>(注：此处使用using 的好处是在进行此次操作后便可释放资源。)</P>
<P><FONT color=#0000ff>利用Connection对象来创建Transaction对象</FONT>：(<FONT color=#0000ff>Transaction对象是ADO.NET中的事务管理对象）</FONT></P>
<P><FONT color=#0000ff>例：</FONT></P>
<P>SqConnection con=new SqlConnection("Provider=SQLOLEDB;Data Source=MyServer;Initial Catalog=database;Integrated Security=SSPI");</P>
<P>con.Open();</P>
<P>OleDbTransaction tran=con.BeginTransaction(); (注：调用此方法会在连接时返回一个新的打开的Transaction对象来进行事务管理）</P>
<P><FONT color=#000000>(注：事务是指一组单一实体运行的语句，可以确保数据的完整性，防止因系统故障或其它原因而引起的数据丢失。概念很抽象，呵呵，看下去就明白了）</FONT></P>
<P><FONT color=#000000>事务有ＡＣＩＤ四个属性（即原子性，一致性，隔离性，持久性）：</FONT></P>
<P><FONT color=#000000><FONT color=#ff0000>原子性</FONT>指在执行事务过程中，这个过程要么成功执行，要么不执行。</FONT></P>
<P><FONT color=#000000><FONT color=#ff0000>一致性</FONT>指事务前和事务后的数据的一致性，也就是如果事务成功执行的话，系统就返回成功的状态，即所有数据的改变标记为已完成，如没完成事务，即回滚，并回到先前的合法状态。</FONT></P>
<P><FONT color=#000000><FONT color=#ff0000>隔离性</FONT>指一个事务内的任何变化都独立于其它的事务（相对于两个事务的说法）</FONT></P>
<P><FONT color=#000000><FONT color=#ff0000>持久性</FONT>指事务是持续的，也就是事务成功完成后的改变是永久的。</FONT></P>
<P>（注：事务有手动和自动两种，本文的主题不在此，事务的介绍在其它篇章会涉及到）</P>
<P><FONT color=#0000ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;取得数据库的架构信息：</FONT></P>
<P>&nbsp;&nbsp;有时你会发觉有需要获取数据库的架构信息来方便程序的运行。可使用OleDbConnection对象的GetOleDbSchemaTable()方法来获取，它需要一个参数用来作返回的架构信息的过滤器，即只获取表中的列或行信息，不写此参数则获取整个表所有列的信息。</P>
<P>例：</P>
<P>OleDbConnectioncon=new OleDbConnection("Provider=SQLOLEDB;Data Source=MyServer;Initial Catalog=database;Integrated Security=SSPI");</P>
<P>con.Open();</P>
<P>DataTable dt=con.GetOleDbSchemaTable(OleDbSchamaGuid,null);</P>
<P>foreach(DataRow row in dt.Rows)</P>
<P>Console.WriteLine(row["column_name"].ToString());</P>
<P>---------------------------------------------------------------</P>
<P>关于AD.NET的连接对象还有很多有用的方法，具体查ＭＳＤＮ。</P><BR><img src ="http://www.blogjava.net/kapok/aggbug/3177.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-04-12 14:59 <a href="http://www.blogjava.net/kapok/archive/2005/04/12/3177.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Using Annotations with a Typed DataSet</title><link>http://www.blogjava.net/kapok/archive/2005/04/12/3175.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Tue, 12 Apr 2005 06:16:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/04/12/3175.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/3175.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/04/12/3175.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/3175.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/3175.html</trackback:ping><description><![CDATA[<DIV id=nstext valign="bottom">
<DIV class=saveHistory id=allHistory onsave="saveAll()" onload="loadAll()"></DIV>
<P><A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconusingannotationswithtypeddataset.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconusingannotationswithtypeddataset.asp</A><BR><BR>Annotations enable you to modify the names of the elements in your typed <B>DataSet</B> without modifying the underlying schema. Modifying the names of the elements in your underlying schema would cause the typed <B>DataSet</B> to refer to objects that do not exist in the data source, as well as losing a reference to the objects that do exist in the data source.</P>
<P>Using annotations, you can customize the names of objects in your typed <B>DataSet</B> with more meaningful names, making code more readable and your typed <B>DataSet</B> easier for clients to use, while leaving underlying schema intact. For example, the following schema element for the <B>Customers</B> table of the <B>Northwind</B> database would result in a <B>DataRow</B> object name of <B>CustomersRow</B> and a <B>DataRowCollection</B> named <B>Customers</B>.</P><PRE class=code>&lt;xs:element name="Customers"&gt;
  &lt;xs:complexType&gt;
    &lt;xs:sequence&gt;
      &lt;xs:element name="CustomerID" type="xs:string" minOccurs="0" /&gt;
    &lt;/xs:sequence&gt;
  &lt;/xs:complexType&gt;
&lt;/xs:element&gt;</PRE>
<P>A <B>DataRowCollection</B> name of <B>Customers</B> is meaningful in client code, but a <B>DataRow</B> name of <B>CustomersRow</B> is misleading because it is a single object. Also, in common scenarios, the object would be referred to without the <B>Row</B> identifier and instead would be simply referred to as a <B>Customer</B> object. The solution is to annotate the schema and identify new names for the <B>DataRow</B> and <B>DataRowCollection</B> objects. Following is the annotated version of the previous schema.</P><PRE class=code>&lt;xs:element name="Customers"<B> codegen:typedName="Customer" codegen:typedPlural="Customers"</B>&gt;
  &lt;xs:complexType&gt;
    &lt;xs:sequence&gt;
      &lt;xs:element name="CustomerID" type="xs:string" minOccurs="0" /&gt;
    &lt;/xs:sequence&gt;
  &lt;/xs:complexType&gt;
&lt;/xs:element&gt;</PRE>
<P>Specifying a <B>typedName</B> value of <B>Customer</B> will result in a <B>DataRow</B> object name of <B>Customer</B>. Specifying a <B>typedPlural</B> value of <B>Customers</B> preserves the <B>DataRowCollection</B> name of <B>Customers</B>.</P>
<P>The following table shows the annotations available for use.</P>
<DIV class=tablediv>
<TABLE class=dtTABLE cellSpacing=0>
<TBODY>
<TR vAlign=top>
<TH width="27%">Annotation</TH>
<TH width="73%">Description</TH></TR>
<TR vAlign=top>
<TD width="27%"><B>typedName</B></TD>
<TD width="73%">Name of the object.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>typedPlural</B></TD>
<TD width="73%">Name of a collection of objects.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>typedParent</B></TD>
<TD width="73%">Name of the object when referred to in a parent relationship.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>typedChildren</B></TD>
<TD width="73%">Name of the method to return objects from a child relationship.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>nullValue</B></TD>
<TD width="73%">Value if the underlying value is <B>DBNull</B>. See the following table for <B>nullValue</B> annotations. The default is <B>_throw</B>.</TD></TR></TBODY></TABLE></DIV>
<P>The following table shows the values that can be specified for the <B>nullValue</B> annotation.</P>
<DIV class=tablediv>
<TABLE class=dtTABLE cellSpacing=0>
<TBODY>
<TR vAlign=top>
<TH width="27%">nullValue</TH>
<TH width="73%">Description</TH></TR>
<TR vAlign=top>
<TD width="27%"><I>Replacement Value</I></TD>
<TD width="73%">Specifies a value to be returned. The returned value must match the type of the element. For example, use <CODE class=ce>nullValue="0"</CODE> to return 0 for null integer fields.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>_throw</B></TD>
<TD width="73%">Throw an exception. This is the default.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>_null</B></TD>
<TD width="73%">Return a null reference or throw an exception if a primitive type is encountered.</TD></TR>
<TR vAlign=top>
<TD width="27%"><B>_empty</B></TD>
<TD width="73%">For strings, return <B>String.Empty</B>, otherwise return an object created from an empty constructor. If a primitive type is encountered, throw an exception.</TD></TR></TBODY></TABLE></DIV>
<P>The following table shows default values for objects in a typed <B>DataSet</B> and the available annotations.</P>
<DIV class=tablediv>
<TABLE class=dtTABLE cellSpacing=0>
<TBODY>
<TR vAlign=top>
<TH width="33%">Object/Method/Event</TH>
<TH width="46%">Default</TH>
<TH width="21%">Annotation</TH></TR>
<TR vAlign=top>
<TD width="33%"><B>DataTable</B></TD>
<TD width="46%">TableNameDataTable</TD>
<TD width="21%">typedPlural</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>DataTable Methods</B></TD>
<TD width="46%">NewTableNameRow 
<P>AddTableNameRow</P>
<P>DeleteTableNameRow</P></TD>
<TD width="21%">typedName</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>DataRowCollection</B></TD>
<TD width="46%">TableName</TD>
<TD width="21%">typedPlural</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>DataRow</B></TD>
<TD width="46%">TableNameRow</TD>
<TD width="21%">typedName</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>DataColumn</B></TD>
<TD width="46%">DataTable.ColumnNameColumn 
<P>DataRow.ColumnName</P></TD>
<TD width="21%">typedName</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>Property</B></TD>
<TD width="46%">PropertyName</TD>
<TD width="21%">typedName</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>Child Accessor</B></TD>
<TD width="46%">GetChildTableNameRows</TD>
<TD width="21%">typedChildren</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>Parent Accessor</B></TD>
<TD width="46%">TableNameRow</TD>
<TD width="21%">typedParent</TD></TR>
<TR vAlign=top>
<TD width="33%"><B>DataSet Events</B></TD>
<TD width="46%">TableNameRowChangeEvent 
<P>TableNameRowChangeEventHandler</P></TD>
<TD width="21%">typedName</TD></TR></TBODY></TABLE></DIV>
<P>To use typed <B>DataSet</B> annotations, you must include the following <B>xmlns</B> reference in your XML Schema definition language (XSD) schema.</P><PRE class=code>xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"</PRE>
<P>The following is a sample, annotated schema that exposes the <B>Customers</B> table of the <B>Northwind</B> database with a relation to the<B> Orders </B>table included.</P><PRE class=code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;xs:schema id="CustomerDataSet" 
      <B>xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"</B>
      xmlns="" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"&gt;
  &lt;xs:element name="CustomerDataSet" msdata:IsDataSet="true"&gt;
    &lt;xs:complexType&gt;
      &lt;xs:choice maxOccurs="unbounded"&gt;
        &lt;xs:element name="Customers"<B> codegen:typedName="Customer" codegen:typedPlural="Customers"</B>&gt;
          &lt;xs:complexType&gt;
            &lt;xs:sequence&gt;
              &lt;xs:element name="CustomerID" <B>codegen:typedName="CustomerID" </B>type="xs:string" minOccurs="0" /&gt;
              &lt;xs:element name="CompanyName" <B>codegen:typedName="CompanyName" </B>type="xs:string" minOccurs="0" /&gt;
              &lt;xs:element name="Phone" <B>codegen:typedName="Phone" codegen:nullValue="" </B>type="xs:string" minOccurs="0" /&gt;
            &lt;/xs:sequence&gt;
          &lt;/xs:complexType&gt;
        &lt;/xs:element&gt;
        &lt;xs:element name="Orders"<B> codegen:typedName="Order" codegen:typedPlural="Orders"</B>&gt;
          &lt;xs:complexType&gt;
            &lt;xs:sequence&gt;
              &lt;xs:element name="OrderID" <B>codegen:typedName="OrderID" </B>type="xs:int" minOccurs="0" /&gt;
              &lt;xs:element name="CustomerID" <B>codegen:typedName="CustomerID" codegen:nullValue="" </B>type="xs:string" minOccurs="0" /&gt;
              &lt;xs:element name="EmployeeID" <B>codegen:typedName="EmployeeID" codegen:nullValue="0" </B>type="xs:int" minOccurs="0" /&gt;
              &lt;xs:element name="OrderDate" <B>codegen:typedName="OrderDate" codegen:nullValue="1980-01-01T00:00:00" </B>type="xs:dateTime" minOccurs="0" /&gt;
            &lt;/xs:sequence&gt;
          &lt;/xs:complexType&gt;
        &lt;/xs:element&gt;
      &lt;/xs:choice&gt;
    &lt;/xs:complexType&gt;
    &lt;xs:unique name="Constraint1"&gt;
      &lt;xs:selector xpath=".//Customers" /&gt;
      &lt;xs:field xpath="CustomerID" /&gt;
    &lt;/xs:unique&gt;
    &lt;xs:keyref name="CustOrders" refer="Constraint1" <B>codegen:typedParent="Customer" codegen:typedChildren="GetOrders"</B>&gt;
      &lt;xs:selector xpath=".//Orders" /&gt;
      &lt;xs:field xpath="CustomerID" /&gt;
    &lt;/xs:keyref&gt;
  &lt;/xs:element&gt;
&lt;/xs:schema&gt;</PRE>
<P>The following code example uses a strongly typed <B>DataSet</B> created from the sample schema. It uses one <B>DataAdapter</B> to populate the <B>Customers</B> table and another <B>DataAdapter</B> to populate the <B>Orders</B> table. The strongly typed <B>DataSet</B> defines the <B>DataRelations</B>.</P><PRE class=code><SPAN class=lang>[Visual&nbsp;Basic]
</SPAN>Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" &amp; _
                                                   "Initial Catalog=northwind")
Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID, CompanyName, Phone FROM Customers", &amp;
                                                  nwindConn)
Dim orderDA As SqlDataAdapter = New SqlDataAdapter("SELECT OrderID, CustomerID, EmployeeID, OrderDate FROM Orders", &amp;
                                                   nwindConn)

' Populate a strongly typed DataSet.
nwindConn.Open()
Dim custDS As CustomerDataSet = New CustomerDataSet()
custDA.Fill(custDS, "Customers")
orderDA.Fill(custDS, "Orders")
nwindConn.Close()

' Add a strongly typed event.
AddHandler custDS.Customers.CustomerChanged, &amp;
           New CustomerDataSet.CustomerChangeEventHandler(AddressOf OnCustomerChanged)

' Add a strongly typed DataRow.
Dim newCust As CustomerDataSet.Customer = custDS.Customers.NewCustomer()
newCust.CustomerID = "NEW01"
newCust.CompanyName = "My New Company"
custDS.Customers.AddCustomer(newCust)

' Navigate the child relation.
Dim customer As CustomerDataSet.Customer
Dim order As CustomerDataSet.Order

For Each customer In custDS.Customers
  Console.WriteLine(customer.CustomerID)
  For Each order In customer.GetOrders()
    Console.WriteLine(vbTab &amp; order.OrderID)
  Next
Next

Private Shared Sub OnCustomerChanged(sender As Object, e As CustomerDataSet.CustomerChangeEvent)

End Sub
<SPAN class=lang>[C#]
</SPAN>SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");
SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName, Phone FROM Customers", nwindConn);
SqlDataAdapter orderDA = new SqlDataAdapter("SELECT OrderID, CustomerID, EmployeeID, OrderDate FROM Orders", nwindConn);

// Populate a strongly typed DataSet.
nwindConn.Open();
CustomerDataSet custDS = new CustomerDataSet();
custDA.Fill(custDS, "Customers");
orderDA.Fill(custDS, "Orders");
nwindConn.Close();

// Add a strongly typed event.
custDS.Customers.CustomerChanged += new 
  CustomerDataSet.CustomerChangeEventHandler(OnCustomerChanged);

// Add a strongly typed DataRow.
CustomerDataSet.Customer newCust = custDS.Customers.NewCustomer();
newCust.CustomerID = "NEW01";
newCust.CompanyName = "My New Company";
custDS.Customers.AddCustomer(newCust);

// Navigate the child relation.
foreach(CustomerDataSet.Customer customer in custDS.Customers)
{
  Console.WriteLine(customer.CustomerID);
  foreach(CustomerDataSet.Order order in customer.GetOrders())
    Console.WriteLine("\t" + order.OrderID);
}

protected static void OnCustomerChanged(object sender, CustomerDataSet.CustomerChangeEvent e)
{

}</PRE>
<H4 class=dtH4>See Also</H4>
<P><A href="http://msdn.microsoft.com/library/en-us/cpguide/html/cpconworkingwithtypeddataset.asp">Working with a Typed DataSet</A> | <A href="http://msdn.microsoft.com/library/en-us/cpguide/html/cpconcreatingusingdatasets.asp">Creating and Using DataSets</A> | <A href="http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDataDataColumnCollectionClassTopic.asp">DataColumnCollection Class</A> | <A href="http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemDataDataSetClassTopic.asp">DataSet Class</A></P><!-- End Content --></DIV><img src ="http://www.blogjava.net/kapok/aggbug/3175.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-04-12 14:16 <a href="http://www.blogjava.net/kapok/archive/2005/04/12/3175.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用ADO.NET轻松操纵数据库(一) </title><link>http://www.blogjava.net/kapok/archive/2005/04/12/3174.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Tue, 12 Apr 2005 05:52:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/04/12/3174.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/3174.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/04/12/3174.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/3174.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/3174.html</trackback:ping><description><![CDATA[<A href="http://blog.csdn.net/jabby12/archive/2004/08/04/64027.aspx">http://blog.csdn.net/jabby12/archive/2004/08/04/64027.aspx</A><BR>ADO.NET提供了Connection来连接数据库，同时也提供了Command对象来查询数据库。同Connection对象一样，Command也有两种：OleDbCommand和SqlCommand.其区别同Connection对象。
<P>　　要操纵数据库，必须先使用Connection来连接到数据库，再创建一个Command来查询。有几种创建方式，例：</P>
<P>SqlCommand cmd;</P>
<P>string strCon="server=localhost;database=Northwind;Trusted_Connection=Yes;";<BR>string strqry="select * from Categories";<BR>SqlConnection con=new SqlConnection(strCon);<BR>con.Open();<BR><FONT color=#ff0000>¹</FONT>cmd=con.CreateCommand(); //这里使用用Connection对象的CreateCommand方法来创建一个Command对象。<BR>cmd.CommandText=strqry;<BR>//SqlDataReader reader=cmd.ExecuteReader();</P>
<P><FONT color=#ff0000>?²</FONT><FONT color=#000000><FONT color=#25437c>cmd=new SqlCommand();?? //直接使用new 关键字来创建<BR>cmd.CommandText=strqry;<BR>?cmd.Connection=con;</FONT></FONT>?? //设置与数据库的连接</P>
<P><FONT color=#ff0000><FONT color=#25437c>　</FONT>³</FONT><FONT color=#808080><FONT color=#000000>cmd=new SqlCommand(strqry,con);　//直接在new的时候带两个参数来创建</FONT></FONT></P>
<P><FONT color=#808080><FONT color=#000000></FONT><BR></FONT><FONT color=#000000>　</FONT><FONT color=#0000ff>执行方式：</FONT></P>
<P><FONT color=#000000>（主要有这么几种，cmd.ExecuteReader();cmd.ExecuteNonQuery();cmd.ExecuteScalar();cmd.ExecuteXmlReader();）</FONT></P>
<P><FONT color=#808080>　</FONT><FONT color=#000000><FONT style="BACKGROUND-COLOR: #d3d3d3">１，ExecuteReader();</FONT>返回一个SqlDataReader对象或OleDbDataReader对象，这个看你的程序的需要去　　做。可以通过这个对象来检查查询结果，它提供了“游水”式的执行方式，即从结果中读取一行之后，移动到另一行，则前一行就无法再用。有一点要注意的是执行之后，要等到手动去调用Read()方法之后，DataReader对象才会移动到结果集的第一行，同时此方法也返回一个Bool值，表明下一行是否可用，返回True则可用，返回False则到达结果集末尾。</FONT></P>
<P><FONT color=#000000>使用DataReader可以提高执行效率，有两种方式可以提高代码的性能：<FONT style="BACKGROUND-COLOR: #deb887">一种是基于序号的查找，一个是使用适当的Get方法来查找。</FONT>因为查询出来的结果一般都不会改变，除非再次改动查询语句，因此可以通过定位列的位置来查找记录。用这种方法有一个问题，就是可能知道一列的名称而不知道其所在的位置，这个问题的解决方案是通过调用DataReader 对象的GetOrdinal()方法，此方法接收一个列名并返回此列名所在的列号。例：</FONT></P>
<P><FONT color=#000000>int id=reader.GetOrdinal("CategoryName");<BR>while(reader.Read())<BR>{<BR>Response.Write(reader[id]);<BR><BR>reader.Close();</FONT></P>
<P><FONT color=#000000>?至于第二种方式很直观，例：</FONT></P>
<P><FONT color=#000000>　while(reader.Read())<BR>{<BR>　　?Response.Write(reader.GetInt32(0).ToString()+" "+reader.GetString(1).ToString()+" <BR>");<BR>}</FONT></P>
<P><FONT color=#000000>　DataReader的GetInt32()和GetString()通过接收一个列号来返回一个列的值，这两种是最常用的，其中　　还有很多其它的类型。</FONT></P>
<P><FONT color=#000000>(注：DataReader对象在调用Close()方法即关闭与数据库的连接，如果在没有关闭之前又重新打开第二个连接，则会产生一条异常信息)</FONT></P>
<P><FONT color=#000000>　<FONT style="BACKGROUND-COLOR: #d3d3d3">2.,ExecuteNonQuery()?</FONT><FONT style="BACKGROUND-COLOR: #ffffff">这个方法并不返回一个DataReader对象，而是返回一个int类型的值，即在执行之后在数据库中所影响的行数。</FONT></FONT></P>
<P><FONT color=#000000>　例：</FONT></P>
<P><FONT color=#000000>　int affectrows=cmd.ExecuteNonQuery();<BR>Response.Write(affectrows +" 条记录受影响");</FONT></P>
<P><FONT color=#000000>?<FONT style="BACKGROUND-COLOR: #d3d3d3">3,ExecuteScalar()</FONT> 这个方法不接受任何参数，仅仅返回查询结果集中的第一行第一列，而忽略了其它的行和列，而且返回的是一个object类型，在使用之前必须先将它强制转换为所需类型。如果返回的仅仅是一个单独的数据元，则可以使用此方法来提高代码的性能。例：</FONT></P>
<P>string strCon="server=localhost;database=Northwind;Trusted_Connection=Yes;";<BR>string strqry="select count(*) from Categories";<BR>SqlConnection con=new SqlConnection(strCon);<BR>con.Open();<BR>SqlCommand cmd=con.CreateCommand();<BR>int i=Convert.ToInt32(cmd.ExecuteScalar());　//必须强制转换</P>
<P>　<FONT style="BACKGROUND-COLOR: #d3d3d3">4,<FONT color=#000000>ExecuteXmlReader() <FONT style="BACKGROUND-COLOR: #ffffff">此方法用于ＸＭＬ操作，返回一个XmlReader对象，由于系统默认没有引用 System.Xml名空间，因此在使用前必须前引入。例：</FONT></FONT></FONT></P>
<P><FONT color=#000000>string strCon="server=localhost;database=Northwind;Trusted_Connection=Yes;";<BR>SqlConnection con=new SqlConnection(strCon);<BR>con.Open();<BR>SqlCommand cmd = new SqlCommand("select * from Categories FOR XML AUTO, XMLDATA", con);<BR>XmlReader xr=cmd.ExecuteXmlReader();<BR>Response.Write(xr.AttributeCount);　　//这里获取当前节点上的属性个数</FONT><FONT color=#000000>?</FONT></P>
<P><FONT color=#000000>xr.Close();</FONT></P>
<P><FONT color=#000000>　执行完毕之后，照样要显式地调用Close()方法，否则会抛出异常。</FONT></P>
<P><FONT color=#0000ff>　使用参数化的查询</FONT></P>
<P><FONT color=#0000ff>　　</FONT><FONT color=#000000>先看一段ＳＱＬ语句：select CategoryID,Description from Categories where CategoryID=? 其中的问号就是一个参数。但在使用的时候必须是带有＠前缀的命名参数，因为.NET数据提供程序不支持这个通用的参数标记“？”.使用参数化的查询可以大大地简化编程，而且执行效率也比直接查询字符串要高，也更方便，很多情况下都需要更改查询字符串，这种方式就提供了方便，只需更改参数的值即可。例：</FONT></P>
<P><FONT color=#000000>　string strCon="server=localhost;database=Northwind;Trusted_Connection=Yes;";<BR>SqlConnection con=new SqlConnection(strCon);<BR>con.Open();<BR>string strqry="select * from Categories where <A href="mailto:CategoryID=@CategoryID">CategoryID=@CategoryID</A>";　//带参数的查询<BR>SqlCommand cmd=new SqlCommand(strqry,con);<BR>cmd.Parameters.Add("@CategoryID",SqlDbType.Int,4);　//给参数赋于同数据库中相同的类型<BR>cmd.Parameters["@CategoryID"].Value="3";　//给参数赋值，可灵活改变<BR>SqlDataReader r=cmd.ExecuteReader();　<BR>while(r.Read())<BR>{<BR>Response.Write(r.GetString(2)+"<BR>");　//取出指定参数列的值<BR>}<BR>con.Close();　//切记关闭</FONT></P>
<P><FONT color=#0000ff>　使用存储过程进行查询</FONT></P>
<P><FONT color=#0000ff>　</FONT><FONT color=#000000>先看段存储过程的形式：create procedure cateproc (@CategoryID int(4)) as select * from Categories where <A href="mailto:CategoryID=@CategoryID">CategoryID=@CategoryID</A>? return。</FONT></P>
<P><FONT color=#000000>　这个是数据库中的存储过程实现方式，要在程序中调用存储过程，一种方法是使用Command对象的　CommandType属性来实现。CommandType有三个枚举值：Text,TableDirect,StoredProcedure。只需将CommandType属性设为第三个值即可实现调用存储过程。例：</FONT></P>
<P>　string strCon="server=localhost;database=Northwind;Trusted_Connection=Yes;";<BR>SqlConnection con=new SqlConnection(strCon);<BR>con.Open();<BR>SqlCommand cmd=con.CreateCommand();<BR>cmd.CommandText="cateproc";<BR>cmd.CommandType=CommandType.StoredProcedure;<BR>cmd.Parameters.Add("@CategoryID",SqlDbType.Int,4);<BR>cmd.Parameters["CategoryID"].Value="2";<BR>SqlDataReader r=cmd.ExecuteReader();<BR>while(r.Read())<BR>{<BR>Response.Write(r.GetString(2)+"<BR>");<BR>}<BR>con.Close();</P>
<P><FONT color=#000000>　其实在程序中实现调用存储过程的方式跟参数化查询很类似，有点旧鞋翻新的味道。</FONT></P>
<P><FONT color=#000000>　<FONT color=#25437c>cmd.CommandType=CommandType.StoredProcedure;这种方式有个缺点，就是当要查询的表，视图或存储过程的名称中有特殊的字符（如空格）的话，则将无法识别。因此</FONT>还有一种方式就是: </FONT></P>
<P><FONT color=#000000>　cmd.CommandText="{Call cateproc(?)}";　//这里是调用存储过程，问号为参数<BR>cmd.CommandType=CommandType.Text;　//关键是这里。</FONT></P>
<P><FONT color=#0000ff>　设置命令执行超时</FONT></P>
<P><FONT color=#0000ff>　</FONT><FONT color=#000000>命令超时是指Command对象在等待结果的时间，（默认为３０秒）如果在３０秒内没执行查询，则Command抛出一个异常。也可以自己进行设置。例：cmd.CommandTimeout=60;</FONT></P>
<P><FONT color=#0000ff>　取消执行查询</FONT></P>
<P><FONT color=#0000ff>　</FONT><FONT color=#000000>有时因某种原因，需要临时取消命令的执行，可调用Command对象的Cancel()方法来退出执行，如果在未执行查询之前，Cancel()将不做任何事。<BR><BR><BR>首先，ADO.NET中使用了DataAdapter 来处理与数据库的联机与脱机。当时开发人员设计了DataAdapter是为了能够处理脱机数据，方便操作，关于这一点，只要调用其Fill()方法即可,这时会在DataSet中创建一个新的名为“Table“的DataTable.要重新指定名可用DataAdapter.Fill(DataSet,“Tabelname“)。此时connection也关闭了。DataAdapter既可以用来提交查询，并将结果存储到DataSet中，也可以用来向数据库传递更改。仅仅使用其Update方法即可达到向数据库提交存储地DatSet中的更改。</P>
<P>&nbsp;&nbsp;&nbsp; DataAdapter将查询的结果存储在DataSet或DataTable对象中，当执行这一过程的时候，DataAdapter使用了一个Command来与数据库通讯，并在内部使用了DataReader来获取查询结果，最后才将结果复制到DataSet新行中去。这也是Fill的过程。如果有两个DataAdapter对象，都使用相同的Connection对象，在创建的时候就会创建两个Connection对象，而不是同一个，这种情况的解决方案是：</P>
<P><BR><FONT style="BACKGROUND-COLOR: #f5f5dc">&nbsp;&nbsp;&nbsp;SqlConnection con=new SqlConnection("server=localhost;database=Northwind;Trusted_Connection=Yes;")<BR>&nbsp;&nbsp;&nbsp;SqlDataAdapter da=new SqlDataAdapter("select CategoryID,Description from Categories",con);<BR>&nbsp;&nbsp;&nbsp;SqlDataAdapter da=new SqlDataAdapter("select CategoryID,Description from Customers",con);</FONT></P>
<P>而不是将查询字符串，单独写成一行。</P>
<P>&nbsp;&nbsp; 有时候可能并不希望DataSet中的架构与数据库中的架构相同，这种情况的解决方案之一是可以采用别名的方法，即<FONT style="BACKGROUND-COLOR: #f5f5dc"><FONT color=#000000>select id as Product ID,amount as Product Amount from product</FONT>;</FONT><FONT style="BACKGROUND-COLOR: #ffffff">另外一种解决方案就是使用DataAdapter提供的TableMappings集合机制，通过它就可以将查询结果映射到DataSet结构中，这种方法更方便，更灵活。TableMappings属性返回一个DataTableMappingsCollection对象，其中包含了一组DataTableMappings，只要DataSet中相应的表名称与数据库中的表名相同，即可以使用它来创建一个映射(DataSet中可以有多个表)。TableMappings里还有一个ColumnMappings属性，其用法与TableMappings相似。其原理是DataAdapter从数据库读取数据后，利用DataReader从结果集中获取列名称，有一点特别要注意，即<FONT style="BACKGROUND-COLOR: #f5f5dc" color=#000000>只能获取列名称而无法获取表名称</FONT>，DataAdapter事先假定表名称为Table,接着遇到映射语句则进行表映射。不说了，看代码：</FONT></P>
<P>&nbsp;<FONT style="BACKGROUND-COLOR: #f5f5dc"> DataColumnMapping colMap;<BR>&nbsp;&nbsp;&nbsp;SqlConnection con=new SqlConnection("server=localhost;database=Northwind;Trusted_Connection=Yes;");<BR>&nbsp;&nbsp;&nbsp;SqlDataAdapter da=new SqlDataAdapter("select CategoryID,Description from Categories",con);<BR>&nbsp;&nbsp;&nbsp;DataSet ds=new DataSet();</FONT></P>
<P><FONT style="BACKGROUND-COLOR: #f5f5dc">&nbsp;&nbsp;&nbsp;DataTableMapping tblMap=da.TableMappings.Add("Table","Ca"); //这里Table为关键，映射表名为Ca</FONT></P>
<P><FONT style="BACKGROUND-COLOR: #f5f5dc">&nbsp;&nbsp;&nbsp;colMap=tblMap.ColumnMappings.Add("CategoryID","ID"); //映射列表<BR>&nbsp;&nbsp;&nbsp;colMap=tblMap.ColumnMappings.Add("Description","描述");<BR>&nbsp;&nbsp;&nbsp;//&nbsp;Response.Write(tblMap.DataSetTable.ToString());<BR>&nbsp;&nbsp;&nbsp;&nbsp;da.Fill(ds);<BR>&nbsp;&nbsp;&nbsp;DataTable dt=ds.Tables["Ca"]; //这里是映射后的表名，如果仍为数据库的表名，则无效，特别注意<BR>&nbsp;&nbsp;&nbsp;this.DataGrid1.DataSource=dt;<BR>&nbsp;&nbsp;&nbsp;this.DataGrid1.DataBind();</FONT></P>
<P>运行代码后就会发现DataGrid1上的列名为ID和描述 (^_^)</P>
<P>（注：使用DataTableMapping 之前要前导入名空间System.Data.Common;）</P>
<P>还可以使用AddRange方法来简化表和列的映射：(一些代码同上面)</P>
<P><FONT style="BACKGROUND-COLOR: #f5f5dc">&nbsp;&nbsp;.......&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;DataTableMapping tblMap=da.TableMappings.Add("Table","Ca");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DataColumnMapping[] colMapArray=new DataColumnMapping[]{new DataColumnMapping("CategoryID","产&nbsp; &nbsp;品号"),new DataColumnMapping("Description","描述")};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tblMap.ColumnMappings.AddRange(colMapArray);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;......&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></P>
<P><FONT style="BACKGROUND-COLOR: #ffffff">这种映射关系只能从数据库中读取展示给用户，如果要将映射后的Table的更改提交给数据库，这时库发现其中列与库中列不同，便会发生异常，DataAdapter 同时也提供了MissingMappingAction属性来处理。</FONT></P>
<P>DataAdapter1.MissingMappingAction=MissingMappingAction.Passthrough/Ignore/Error</P>
<P>它接受MissingMappingAction的枚举值，Passthrough这个值表示如果在库中找不到与DataSet中相同列的话，就将此列映射到库中，Ignore枚举值表示忽略示出现的列，Error表示找不到相应的列则抛出异常。</P>
<P>分页：</P>
<P>分页在应用中是常有的事，而DataAdapter本身也提供了分页的简单功能，如：<FONT style="BACKGROUND-COLOR: #f5f5dc">DataAdapter1.Fill(dataset,startrow,rownum,“tablename“)</FONT>这种功能用于数据量较小的查询就可以，但当有大量数据的时候，就会发现这种分页的问题的存在。它的原理是假如有一百行数据，分成十页，每页十行，当获取每一页的时候，返回前１０行，再接着，第二页，删除了前１０行而获取接下的１０行，在这一次中，只是为了获取１０行数据，但数据库却返回了２０行，依此类推，第１０页的时候就会返回１００行，而DataAdapter本身就帮我们删除了９０行，因为我们看上去返回的还是１０行，这种性能太低。因此本篇继续介绍另外一种性能较高的分页方法。实际上这种分页方法是将上一页最后一行的键值存储下来，直接在SQL语句中就过滤掉了，不象前面那种到DataAdapter这边才过滤掉。例：</P>
<P><FONT style="BACKGROUND-COLOR: #f5f5dc">con=new SqlConnection("server=localhost;database=Northwind;Trusted_Connection=Yes;");<BR>da=new SqlDataAdapter("select top 50 CustomerID,CompanyName from Customers&nbsp;where　CustomerID&gt;'BOTTM'",con);&nbsp;<BR>ds=new DataSet();<BR>da.Fill(ds,"Categories");<BR>this.DataGrid1.DataSource=ds.Tables["Categories"];&nbsp;this.DataGrid1.DataBind();<BR>con.Close();</FONT></P>
<P>这里假如上一页最后一个键值为”BOTTM”，可以将它用参数替代掉，这样就查出了在'BOTTM'之后的５０行。这种方法实现简单效率也高。</P></FONT><img src ="http://www.blogjava.net/kapok/aggbug/3174.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-04-12 13:52 <a href="http://www.blogjava.net/kapok/archive/2005/04/12/3174.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Implementing Data Transfer Object in .NET with a Typed DataSet</title><link>http://www.blogjava.net/kapok/archive/2005/04/12/3173.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Tue, 12 Apr 2005 04:49:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/04/12/3173.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/3173.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/04/12/3173.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/3173.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/3173.html</trackback:ping><description><![CDATA[<H1 class=dtH1><A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpatterns/html/ImpDTOtypedDataSet.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpatterns/html/ImpDTOtypedDataSet.asp</A></H1>
<H1 class=dtH1><A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconworkingwithtypeddataset.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconworkingwithtypeddataset.asp</A></H1>
<H1 class=dtH1>Implementing Data Transfer Object in .NET with a Typed DataSet</H1>
<P>
<TABLE cellSpacing=0 cellPadding=0 bgColor=#eeeeee>
<TBODY>
<TR>
<TD><IMG height=26 alt=? src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_TL.gif" width=26 border=0></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Data Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Application Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_A1-up.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Deployment Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_D1.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Infrastructure Column: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_toptab_I1.gif" width=45 border=0></A></TD></TR>
<TR>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Architecture Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_A.gif" width=26 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Data Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_1.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Application Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_2.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Deployment Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_3.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Infrastructure Architecture: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_4.gif" width=45 border=0></A></TD></TR>
<TR>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/designpatoverview.aspx"><IMG height=26 alt="Design Row: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_D.gif" width=26 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Data Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_5.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Application Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_6.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Deployment Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_7.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Infrastructure Design: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_8.gif" width=45 border=0></A></TD></TR>
<TR>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/implpatoverview.aspx"><IMG height=26 alt="Implementation Row" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_sidetab_I-up.gif" width=26 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Data Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_9.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Application Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_10-up.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Deployment Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_11.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MSpatterns.asp"><IMG height=26 alt="Infrastructure Implementation: select for more on pattern organization" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_12.gif" width=45 border=0></A></TD></TR>
<TR>
<TD><IMG height=27 alt=? src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_BL.gif" width=26 border=0></TD>
<TD><A href="http://msdn.microsoft.com/practices"><IMG height=27 alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo1.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/practices"><IMG height=27 alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo2.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/practices"><IMG height=27 alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo3.gif" width=37 border=0></A></TD>
<TD><A href="http://msdn.microsoft.com/practices"><IMG height=27 alt="Complete List of patterns &amp; practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/MapNav_logo4.gif" width=45 border=0></A></TD></TR></TBODY></TABLE></P>
<P>Version 1.0.0</P>
<P><A href="http://www.gotdotnet.com/Community/Workspaces/workspace.aspx?id=0aac3f2c-53c1-45d1-b79d-81f7c9382cc7"><FONT color=gray>GotDotNet community for collaboration on this pattern</FONT></A></P>
<P><A href="http://msdn.microsoft.com/practices/"><FONT color=gray>Complete List of patterns &amp; practices</FONT></A></P>
<P></P>
<H2 class=dtH1>
<P>Context</P></H2>
<P>You are implementing a distributed application with the .NET Framework. The client application displays a form that requires making multiple calls to an ASP.NET Web service to satisfy a single user request. Based on performance measurements you have found that making multiple calls degrades application performance. To increase performance, you would like to retrieve all the data that the user request requires in a single call to the Web service. </P>
<H2 class=dtH1>
<P>Background </P></H2>
<BLOCKQUOTE class=dtBlock>
<P>
<P><B>Note:</B> The following is the same sample application that is described in <A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/ImpDTODataSet.asp"><I>Implementing Data Transfer Object in .NET with a DataSet</I></A>. </P>
<P></P>
<P>
<P>The following is a simplified Web application that communicates with an ASP.NET Web service to deliver recording and track information to the user. The Web service in turn calls a database to provide the data that the client requests. The following sequence diagram depicts the interaction among the application, the Web service, and the database for a typical page. </P>
<P></P></BLOCKQUOTE>
<P><IMG src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_DTO_with_DataSet_Fig01.gif"></P>
<P><HEAD3>Figure 1: Behavior of a typical user request</HEAD3></P>
<P>
<P>Figure 1 illustrates the sequence of calls needed to fulfill the entire user request. The first call retrieves the recording information, and the second call retrieves the track information for the specified recording. In addition, the Web service must make separate calls to the database to retrieve the required information. </P>
<P></P>
<H3 class=dtH1>
<P>Database Schema</P></H3>
<P></P>
<P>
<P>The schema that is used in the example shown in Figure 2 depicts a <B>recording</B> record that has a one-to-many relationship with a <B>track</B> record. </P>
<P></P>
<P><IMG src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_DTO_with_DataSet_Fig02.gif"></P>
<P><HEAD3>Figure 2: Schema for sample application</HEAD3></P>
<H3 class=dtH1>
<P>Implementing a DTO</P></H3>
<P></P>
<P>
<P>One way to improve the performance of this user request is to package all the required data into a data transfer object (DTO) that can be sent with a single call to the Web service. This reduces the overhead associated with two separate calls and allows you to use a single connection with the database to retrieve both the recording and the track information. For a detailed description of how this improves performance, see the <A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/DesDTO.asp"><I>Data Transfer Object</I></A> pattern. </P>
<P></P>
<H2 class=dtH1>
<P>Implementation Strategy</P></H2>
<P>A typed <B>DataSet</B> is a generated subclass of <B>System.Data.DataSet</B>. You provide an XML schema file which is then used to generate a strongly-typed wrapper around the <B>DataSet</B>. The following two code samples illustrate the differences. The first sample is implemented with an ordinary <B>DataSet</B>: </P><PRE class=code> 

DataTable dataTable = dataSet.Tables["recording"];
DataRow row = dataTable.Rows[0];
string artist = (string)row["artist"];
 </PRE>
<P>This sample indicates that you need to know the table and column names to access the tables and fields contained in the <B>DataSet</B>. You also have to know the return type of the Artist field to ensure that the correct cast is done. If you do not use the correct type, you will get a runtime error. The following is the same example implemented with a typed <B>DataSet</B>:</P><PRE class=code> 

   Recording recording = typedDataSet.Recordings[0];
   string artist = recording.Artist; 
 </PRE>
<P>This example demonstrates the benefits that the typed interface provides. You no longer have to refer to table or column by name and you do not have to know that the return type of the Artist column is a string. A typed <B>DataSet</B> defines a much more explicit interface that is verifiable at compile time instead of at runtime. In addition to the strongly-typed interface a typed <B>DataSet</B> also can be used in all places a <B>DataSet</B> can be used; therefore, it also can be used as a DTO. It is loaded in a similar fashion as a <B>DataSet</B> and it can be serialized to and from XML. In comparison to an ordinary <B>DataSet</B> you do have to write and maintain an XML schema that describes the typed interface. The Microsoft Visual Studio .NET development system provides a number of tools that simplify the creation and maintenance of the schema.The rest of this implementation strategy outlines the steps required in creating a typed <B>DataSet</B> for the sample application just described. </P>
<H3 class=dtH1>
<P>Creating a Typed DataSet</P></H3>
<P></P>
<P>
<P>A typed DataSet is generated from an XML schema. Visual Studio .NET provides a drag-and-drop tool which automates the creation of the schema (see Figure 3) and the generation of the typed DataSet classes. If you do not use Visual Studio.NET, you can write the XML schema and use a command-line tool called XSD.exe to generate the typed DataSet. For detailed instructions on both of these methods, see "Typed DataSets in ADO.NET" from the May 2001 issue of <I>.NET Developer</I> [Wildermuth02]. </P>
<P></P>
<P><IMG src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/Imp_DTO_with_Typed_DataSet_Fig03.gif"></P>
<P><HEAD3>Figure 3: Visual Studio .NET DataSet file type</HEAD3></P>
<H4 class=dtH1>
<P>RecordingDto.xsd</P></H4>
<P></P>
<P>
<P>The following is the XML schema for the DTO to be used in this example. It combines both the recording table along with its associated track records in a single typed DataSet named <B>RecordingDto</B>:</P>
<P></P><PRE class=code> 

&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;xs:schema id="RecordingDto" targetNamespace="http://msdn.microsoft.com/practices/RecordingDto.xsd"
   elementFormDefault="qualified" attributeFormDefault="qualified" xmlns="http://tempuri.org/RecordingDTO.xsd"
   xmlns:mstns="http://msdn.microsoft.com/practices/RecordingDto.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"
   xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"&gt;
   &lt;xs:element name="RecordingDto" msdata:IsDataSet="true"&gt;
      &lt;xs:complexType&gt;
         &lt;xs:choice maxOccurs="unbounded"&gt;
            &lt;xs:element name="recording" codegen:typedName="Recording" codegen:typedPlural="Recordings"
               codegen:typedChildren="Track"&gt;
               &lt;xs:complexType&gt;
                  &lt;xs:sequence&gt;
                     &lt;xs:element name="id" type="xs:long" codegen:typedName="Id" /&gt;
                     &lt;xs:element name="title" type="xs:string" codegen:typedName="Title" /&gt;
                     &lt;xs:element name="artist" type="xs:string" codegen:typedName="Artist" /&gt;
                  &lt;/xs:sequence&gt;
               &lt;/xs:complexType&gt;
            &lt;/xs:element&gt;
            &lt;xs:element name="track" codegen:typedName="Track" codegen:typedPlural="Tracks" codegen:typedParent="Recording"&gt;
               &lt;xs:complexType&gt;
                  &lt;xs:sequence&gt;
                     &lt;xs:element name="id" type="xs:long" codegen:typedName="Id" /&gt;
                     &lt;xs:element name="title" type="xs:string" codegen:typedName="Title" /&gt;
                     &lt;xs:element name="duration" type="xs:string" codegen:typedName="Duration" /&gt;
                     &lt;xs:element name="recordingId" type="xs:long" codegen:typedName="RecordingId" /&gt;
                  &lt;/xs:sequence&gt;
               &lt;/xs:complexType&gt;
            &lt;/xs:element&gt;
         &lt;/xs:choice&gt;
      &lt;/xs:complexType&gt;
      &lt;xs:unique name="RecordingDTOKey1" msdata:PrimaryKey="true"&gt;
         &lt;xs:selector xpath=".//mstns:recording" /&gt;
         &lt;xs:field xpath="mstns:id" /&gt;
      &lt;/xs:unique&gt;
      &lt;xs:unique name="RecordingDTOKey2" msdata:PrimaryKey="true"&gt;
         &lt;xs:selector xpath=".//mstns:track" /&gt;
         &lt;xs:field xpath="mstns:id" /&gt;
      &lt;/xs:unique&gt;
      &lt;xs:keyref name="recordingtrack" refer="mstns:RecordingDTOKey1"&gt;
         &lt;xs:selector xpath=".//mstns:track" /&gt;
         &lt;xs:field xpath="mstns:recordingId" /&gt;
      &lt;/xs:keyref&gt;
   &lt;/xs:element&gt;
&lt;/xs:schema&gt;
 </PRE>
<P>This schema is not the exact file produced by Visual Studio .NET. It is annotated with a number of attributes that are prefixed from the <B>codegen</B> namespace. This modification is desirable because the code that is generated does not adhere to the .NET naming conventions. For example, without the modification, Visual Studio .NET would generate a <B>track</B> class that corresponds to the track table, whereas according to conventions used in the .NET Framework the class should be named <B>Track</B>. To change the name of the class that is generated, you must add the codegen:typedName attribute to the element definition in the XML schema:</P><PRE class=code> 

&lt;xs:element name="track" codegen:typedName="Track"&gt;
   
&lt;/element&gt;
 </PRE>
<P>There are a number of other attributes besides codegen:typedName. For a detailed description of all the attributes, see "Typed DataSets in ADO.NET" from the May 2001 issue of <I>.NET Developer</I> [Wildermuth02].</P>
<H3 class=dtH1>
<P>Filling a Typed DataSet from the Database</P></H3>
<P></P>
<P>
<P>The following code example demonstrates how to fill a typed <B>DataSet</B> with the data that the sample application requires. This includes the specific <B>recording</B> record and all of its associated <B>track</B> records. The difference between this code and filling an ordinary <B>DataSet</B> is that you do not need to explicitly define the relationship between the recording and track records. </P>
<P></P>
<H4 class=dtH1>
<P>Assembler.cs</P></H4>
<P></P>
<P>
<P>Just as in <I>Implementing a Data Transfer Object in .NET with a DataSet</I>, an <B>Assembler</B> class maps the actual database calls into the typed <B>DataSet</B>: </P>
<P></P><PRE class=code> 

using System;
using System.Data;
using System.Data.SqlClient;

using Recording;

public class Assembler
{
   public static RecordingDto CreateRecordingDto(long id)
   {
      string selectCmd = 
         String.Format(
         "select * from recording where id = {0}",
         id);

      SqlConnection myConnection = 
         new SqlConnection(
         "server=(local);database=recordings;Trusted_Connection=yes;");
      SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, 
         myConnection);

      RecordingDto dto = new RecordingDto();
      myCommand.Fill(dto, "recording");

      String trackSelect = 
         String.Format(
         "select * from Track where recordingId = {0} order by Id",
         id);

      SqlDataAdapter trackCommand = 
         new SqlDataAdapter(trackSelect, myConnection);
      trackCommand.Fill(dto, "track");

      return dto;
   }
}
 </PRE>
<BLOCKQUOTE class=dtBlock>
<P>
<P><B>Note:</B> The example shown here is not meant to describe the only way to fill the typed <B>DataSet</B>. There are many ways to retrieve this data from the database. For example, you could use a stored procedure. </P>
<P></P></BLOCKQUOTE>
<H3 class=dtH1>
<P>Using a Typed DataSet in an ASP.NET Page</P></H3>
<P></P>
<P>
<P>As mentioned previously, a typed <B>DataSet</B> inherits from <B>System.Data.DataSet</B>. This means that it can be substituted for a <B>DataSet</B>. For example, when using the .NET user interface controls (Web Forms or Windows Forms) a typed <B>DataSet</B> can be used in all places you could use a <B>DataSet</B>. The sample application page shown in the following code example uses two <B>DataGrid</B> controls, <B>RecordingGrid</B> and <B>TrackGrid</B>. You can use the typed <B>DataSet</B>, <B>RecordingDto</B> when setting the <B>DataSource</B> properties on the controls because a typed <B>DataSet</B> inherits from <B>DataSet</B>. </P>
<P></P><PRE class=code> 

using System;
using System.Data;
using RecordingApplication.localhost;

public class RetrieveForm : System.Web.UI.Page
{
   private RecordingCatalog catalog = new RecordingCatalog();
 
   // 

   protected void Button1_Click(object sender, System.EventArgs e)
   {
      string stringId = TextBox1.Text;
      long id = Convert.ToInt64(stringId);

      RecordingDTO dto = catalog.Get(id);
      RecordingGrid.DataSource = dto.recording;
      RecordingGrid.DataBind();

      TrackGrid.DataSource = dto.track;
      TrackGrid.DataBind();
   }
}
 </PRE>
<H2 class=dtH1>
<P>Tests</P></H2>
<P>Because the typed <B>DataSet</B> is generated by tools in the .NET Framework, you do not need to write tests to verify that it functions correctly. In the following tests, you are testing that the <B>Assembler</B> class loaded the typed <B>DataSet</B> correctly. </P>
<H3 class=dtH1>
<P>AssemblerFixture.cs</P></H3>
<P></P><PRE class=code> 

using NUnit.Framework;
using System.Data;
using Recording;

[TestFixture]
public class AssemblerFixture
{
   private RecordingDto dto;
   private RecordingDto.Recording recording;
   private RecordingDto.Track[] tracks; 
   
   [SetUp]
   public void Init()
   {
      dto = Assembler.CreateRecordingDto(1234);
      recording = dto.Recordings[0];
      tracks = recording.GetTracks();
   }

   [Test]
   public void RecordingCount()
   {
      Assert.Equals(1, dto.Recordings.Rows.Count);
   }

   [Test]
   public void RecordingTitle()
   {
      Assert.Equals("Up", recording.Title.Trim());
   }


   [Test]
   public void RecordingChild()
   {
      Assert.Equals(10, tracks.Length);

      foreach(RecordingDto.Track track in tracks)
      {
         Assert.Equals(recording.Id, track.RecordingId);
      }
   }

   [Test]
   public void TrackParent()
   {
      RecordingDto.Track track = tracks[0];
      RecordingDto.Recording parent = track.Recording;
      Assert.Equals("Up", parent.Title.Trim());
   }

   [Test]
   public void TrackContent()
   {
      RecordingDto.Track track = tracks[0];
      Assert.Equals("Darkness", track.Title.Trim());
   }

   [Test]
   public void InvalidRecording()
   {
      RecordingDto dto = Assembler.CreateRecordingDto(-1);
      Assert.Equals(0, dto.Recordings.Rows.Count);
      Assert.Equals(0, dto.Tracks.Rows.Count);
   }
}
 </PRE>
<P>These tests describe how to access the individual elements of the <B>DataSet</B>. Because of the use of a typed <B>DataSet</B>, the test code does not require the actual column names and does not require the return type to be cast. Comparing these tests with the ones described in <I>Implementing Data Transfer Object in .NET with a DataSet</I> reveals the differences between using a strongly-typed interface and a generic interface. The strongly-typed interface is easier to use and understand. It also provides the added benefit of compile-time checking on return types. 
<H2 class=dtH1>
<P>Resulting Context</P></H2>
<P>Implementing DTO with a typed <B>DataSet</B> shares a number of the same benefits and liabilities as implementing DTO with a <B>DataSet</B>; however, certain benefits and liabilities are unique to a typed-<B>DataSet</B> implementation.</P>
<H3 class=dtH1>
<P>Benefits</P></H3>
<P></P>
<P>
<P>The typed <B>DataSet</B> shares the following benefits with a <B>DataSet</B> when used as a DTO: </P>
<P></P>
<LI>
<P><B>Development tool support</B>. Because the <B>DataSet</B> class is implemented in ADO.NET, there is no need to design and implement the DTO. There is also extensive support in Visual Studio for automating the creation and filling of <B>DataSet</B> and typed-<B>DataSet</B> objects. </P>
<LI>
<P><B>Integration with controls</B>. A <B>DataSet</B> works directly with the built-in controls in Windows Forms and Web Forms, making it a logical choice as a DTO. </P>
<LI>
<P><B>Serialization</B>. The <B>DataSet</B> comes complete with the ability to serialize itself into XML. Not only is the content serialized, but the schema for the content is also present in the serialization. </P>
<LI>
<P><B>Disconnected database model</B>. The <B>DataSet</B> represents a snapshot of the current contents of the database. This means that you can alter the contents of the <B>DataSet</B> and subsequently use the <B>DataSet</B> as the means to update the database. </P>
<LI>
<P>An additional benefit that might persuade you to use a typed <B>DataSet</B> as opposed to an ordinary <B>DataSet</B> is the strongly-typed interface of the typed <B>DataSet</B>. A typed <B>DataSet</B>, as described here, generates classes that can be used to access the contained data. The classes present an interface which defines how the class is to be used in a more explicit manner. This removes the need for casting which was present in the <B>DataSet</B> implementation. </P>
<H3 class=dtH1>
<P>Liabilities</P></H3>
<P></P>
<P>
<P>The typed <B>DataSet</B> shares the following liabilities with a <B>DataSet</B> when used in the context of a DTO: </P>
<P></P>
<LI>
<P><B>Interoperability</B>. Because the <B>DataSet</B> class is part of ADO.NET, it is not the best choice for a DTO in cases requiring interoperability with clients that are not running the .NET Framework.. You can still use <B>DataSet</B>, however, the client will be forced to parse the XML and build its own representation. If interoperability is a requirement, see <I>Implementing Data Transfer Object in .NET with Serialized Objects</I>. </P>
<LI>
<P><B>Stale data</B>. The typed <B>DataSet</B>, like a <B>DataSet</B>, is disconnected from the database. It is filled with a snapshot of the data in the database when it is constructed. This implies that the actual data in the database may be different from what is contained in the typed <B>DataSet</B>. For reading primarily static data, this is not a major issue. If the data is constantly changing, however, using any kind of <B>DataSet</B> is not recommended. </P>
<LI>
<P><B>Potential for performance degradation</B>. Instantiating and filling a <B>DataSet</B> can be an expensive operation. Serializing and deserializing a <B>DataSet</B> can also be very time consuming. A good rule of thumb for using a <B>DataSet</B> is that a <B>DataSet</B> is a good choice when you are using more than one table or relying on the capability of the <B>DataSet</B> to update the database. If you are displaying the results from a single table, then using a <B>DataReader</B> with strongly-typed objects may offer better performance. For more information, see <I>Implementing Data Transfer Object in .NET with Serialized Objects</I>. </P>
<LI>
<P>The following are additional liabilities when using a typed <B>DataSet</B> as opposed to an ordinary <B>DataSet</B>: </P>
<LI>
<P><B>A typed DataSet is still a DataSet. </B>A typed <B>DataSet</B> can be substituted at runtime with a <B>DataSet</B>. This means that even though the strongly-typed interface exists, programmers can still access the data without the typed interface. A possible result of doing this is that there could be parts of the code which couple the application tightly to the <B>DataSet</B> table and column names. </P>
<LI>
<P><B>The need for an XML schema</B>. When using a typed DataSet you have to create and maintain an XML schema to describe the strongly-typed interface. Visual Studio .NET provides a number of tools to assist in this process, but nevertheless you still have to maintain an additional file. </P>
<H2 class=dtH1>
<P>Related Patterns</P></H2>
<P>For more information, see the following related patterns:</P>
<LI>
<P><A href="http://msdn.microsoft.com/library/en-us/dnpatterns/html/ImpDTODataSet.asp"><I>Implementing Data Transfer Object in .NET with a DataSet</I></A>.</P>
<LI>
<P><I>Implementing Data Transfer Object in .NET with Serialized Objects</I>.</P>
<LI>
<P><I>Assembler</I>. In <I>Enterprise Application Architecture Patterns</I>, Fowler defines <I>Assembler</I> as a specialized instance of the <I>Mapper</I> pattern <I>[Fowler03].</I></P>
<H2 class=dtH1>
<P>Acknowledgments</P></H2>
<P>[Beau02] Beauchemin, Bob. <I>Essential ADO.NET</I>. Addison-Wesley, 2002.</P>
<P>[Fowler03] Fowler, Martin. <I>Enterprise Application Architecture Patterns</I>. Addison-Wesley, 2003.</P>
<P>[Wildermuth01] Wildermuth, Shawn. "Typed DataSets in ADO.NET." <I>.NET Developer</I>. May 2001.</P>
<P><IMG alt="Patterns Practices" src="http://msdn.microsoft.com/library/en-us/dnpatterns/html/PATTPRAC.gif"></P><!-- End Content --></LI><img src ="http://www.blogjava.net/kapok/aggbug/3173.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-04-12 12:49 <a href="http://www.blogjava.net/kapok/archive/2005/04/12/3173.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>.Net链接随手贴</title><link>http://www.blogjava.net/kapok/archive/2005/03/18/2200.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Fri, 18 Mar 2005 07:49:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/03/18/2200.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/2200.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/03/18/2200.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/2200.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/2200.html</trackback:ping><description><![CDATA[<A href="http://ms.mblogger.cn/dotM">http://ms.mblogger.cn/dotM</A><BR><BR><A href="http://www.cnblogs.com/tintown/category/12787.html">http://www.cnblogs.com/tintown/category/12787.html</A><BR><BR><A href="http://www.hidotnet.com/documents/DotNetTools.htm">http://www.hidotnet.com/documents/DotNetTools.htm</A><BR><BR><A href="http://www.remotesoft.com/dotexplorer/">http://www.remotesoft.com/dotexplorer/</A><BR><BR><A href="http://download.cnblogs.com/dahuzizyd/">http://download.cnblogs.com/dahuzizyd/</A><BR><BR><A href="http://www.phcx.net/yougve/bbs/showthread.asp?threadid=593&amp;goto=prev">http://www.phcx.net/yougve/bbs/showthread.asp?threadid=593&amp;goto=prev</A><BR><BR><A href="http://www.syncfusion.com/FAQ/WinForms/default.asp">http://www.syncfusion.com/FAQ/WinForms/default.asp</A><BR><BR><A href="http://www.cnblogs.com/tintown/archive/2005/01/16/92730.html">http://www.cnblogs.com/tintown/archive/2005/01/16/92730.html</A><BR><BR><A href="http://www.smartprise.com/tintown/backup/NetAdvantage/2004.3/NetAdvantage2004Vol3ASPNET.rar">http://www.smartprise.com/tintown/backup/NetAdvantage/2004.3/NetAdvantage2004Vol3ASPNET.rar</A><img src ="http://www.blogjava.net/kapok/aggbug/2200.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-03-18 15:49 <a href="http://www.blogjava.net/kapok/archive/2005/03/18/2200.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Reflector、PInvoke.NET、XP&amp;ADHelper </title><link>http://www.blogjava.net/kapok/archive/2005/03/18/2198.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Fri, 18 Mar 2005 07:25:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/03/18/2198.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/2198.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/03/18/2198.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/2198.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/2198.html</trackback:ping><description><![CDATA[<A href="http://blog.joycode.com/liuhuimiao/archive/2004/05/09/21070.aspx">http://blog.joycode.com/liuhuimiao/archive/2004/05/09/21070.aspx</A><img src ="http://www.blogjava.net/kapok/aggbug/2198.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-03-18 15:25 <a href="http://www.blogjava.net/kapok/archive/2005/03/18/2198.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>.Net问题集</title><link>http://www.blogjava.net/kapok/archive/2005/03/18/2197.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Fri, 18 Mar 2005 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/03/18/2197.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/2197.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/03/18/2197.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/2197.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/2197.html</trackback:ping><description><![CDATA[<A href="http://www.zahui.com/html/14/">http://www.zahui.com/html/14/</A><img src ="http://www.blogjava.net/kapok/aggbug/2197.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-03-18 15:23 <a href="http://www.blogjava.net/kapok/archive/2005/03/18/2197.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Resharper crack logs</title><link>http://www.blogjava.net/kapok/archive/2005/03/18/2195.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Fri, 18 Mar 2005 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/03/18/2195.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/2195.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/03/18/2195.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/2195.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/2195.html</trackback:ping><description><![CDATA[<A href="http://www.cnblogs.com/feidao/archive/2004/08/12/32537.aspx">http://www.cnblogs.com/feidao/archive/2004/08/12/32537.aspx</A><img src ="http://www.blogjava.net/kapok/aggbug/2195.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-03-18 14:45 <a href="http://www.blogjava.net/kapok/archive/2005/03/18/2195.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>不错的工具:Reflector for .NET </title><link>http://www.blogjava.net/kapok/archive/2005/03/18/2194.html</link><dc:creator>笨笨</dc:creator><author>笨笨</author><pubDate>Fri, 18 Mar 2005 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/kapok/archive/2005/03/18/2194.html</guid><wfw:comment>http://www.blogjava.net/kapok/comments/2194.html</wfw:comment><comments>http://www.blogjava.net/kapok/archive/2005/03/18/2194.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/kapok/comments/commentRss/2194.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/kapok/services/trackbacks/2194.html</trackback:ping><description><![CDATA[<DIV class=postTitle><A href="http://www.cnblogs.com/dudu/archive/2004/03/09/2557.aspx">http://www.cnblogs.com/dudu/archive/2004/03/09/2557.aspx</A><A class=postTitle2 id=viewpost1_TitleUrl href="http://www.cnblogs.com/dudu/archive/2004/03/09/2557.html"><BR><BR>不错的工具:Reflector for .NET </A></DIV>
<P>今天想找一个Class浏览工具，就像VS.NET中的对象浏览器。后来在<A href="http://www.dotnettoolbox.com/toolbox/ViewCategory.aspx?ID=5">http://www.dotnettoolbox.com/toolbox/ViewCategory.aspx?ID=5</A>（这个网站也是个不错的地方）发现这个工具：Reflector for .NET 。<BR><BR><STRONG>网址</STRONG>:<BR><A href="http://www.aisto.com/roeder/dotnet/">http://www.aisto.com/roeder/dotnet/</A><BR><STRONG>下载地址</STRONG>: <BR><A href="http://www.aisto.com/roeder/dotnet/">http://www.aisto.com/roeder/dotnet/</A> <BR>注意：下载时要输一些注册信息，输入用户名时，中间要加一个空格。<BR><STRONG>功能介绍：<BR></STRONG>Reflector is a class browser for .NET components (assemblies). It supports assembly and namespace views, type and member search, C# XML documentation viewer, reference search, IL disassembler, VB and C# decompiler, dependency trees, supertype/subtype hierarchies and resource viewers. Function prototypes are displayed in C# and VB syntax. <BR></P><img src ="http://www.blogjava.net/kapok/aggbug/2194.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/kapok/" target="_blank">笨笨</a> 2005-03-18 14:43 <a href="http://www.blogjava.net/kapok/archive/2005/03/18/2194.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>