﻿<?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>IT博客-sugar-随笔分类-ASP.NET</title><link>http://www.cnitblog.com/sugar/category/837.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 06:53:37 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 06:53:37 GMT</pubDate><ttl>60</ttl><item><title>如何进行.NET高效开发</title><link>http://www.cnitblog.com/sugar/archive/2006/03/12/7511.html</link><dc:creator>sugar</dc:creator><author>sugar</author><pubDate>Sun, 12 Mar 2006 05:53:00 GMT</pubDate><guid>http://www.cnitblog.com/sugar/archive/2006/03/12/7511.html</guid><wfw:comment>http://www.cnitblog.com/sugar/comments/7511.html</wfw:comment><comments>http://www.cnitblog.com/sugar/archive/2006/03/12/7511.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sugar/comments/commentRss/7511.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sugar/services/trackbacks/7511.html</trackback:ping><description><![CDATA[<SPAN id=dgfiList__ctl3_Body>摘自： <BR>http://fabu.beareyes.com.cn/2/lib/200510/08/20051008242.htm <BR>http://www.veryol.com/news/dongtai/hard/viedo/2005-10-08-19068.htm&nbsp; <BR>http://doc.intozgc.com/200510/08/00068600.shtml <BR><BR>一、面向对象的.NET开发 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;.NET与JAVA一样是一种面向对象的程序语言，面向对象的程序开发具有续承性、封装性、多态性等多种高级特性。这种方式的程序开发的思维方法与我们现实生活中习惯的思维方式是相似的。.NET可以轻松创建对象，并拥有所有面向对向语言所具有的特性。面向对象是.NET可以高效开发的基础，我们现在从几个方面讲述如何高效创建面向对象的.NET程序。 <BR><BR>二、.NET程序的层次结构 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;如何对程序进行合理的分层会对项目的开发效率、程序的维护性等有极大的影响，所以必须重视对程序合理分层。一种较为细致、合理的分层是将程序分为四层，从下到上分为：数据结构层、数据操作层、.NET对象层、表示层。如下图：&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/1.gif" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/1.gif" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/1.gif"></A> <BR><BR>数据结构层（SqlServer或Oracle）：这一层是整个系统中最为核心的一层，这一层的内容为：数据库表、索引、关系等最低层内容。所有的需求都在这一层能够体现，也是开发人员必须花费大量时间进行设计的一层。我们可以通过PowerDesign或ERStudio等工作先进行数据库模型的设计，将数据库模型设计到最优，然后转化成物理数据库。 <BR><BR>数据库操作层（存储过程）：数据结构上面的是操作数据库的存储过程，在.NET开发中应有所有对数据库的操作均由存储过程来进行的习惯。存储过程中基本的方法有：Add(添加一条记录)、Delete（删除一条记录）、Update（更新一条记录）、Load（加载一条记录）、List(读取记录列表)。其他可以根据需要篇写相应的存储过程。 <BR><BR>.NET对象层：为每个表创建一个对象，在数据库与程序间进行映射，使数据库结构与程序结构一一对应。将表中的字段映射为对象的属性，针对表操作的存储过程映射为方法； <BR><BR>表示层（WindowForm或WebForm）：表示层可以是网页也可以是Window程序的界面 <BR><BR>三、对象的结构 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;让我们先看看数据库的结构，以SqlServer为例数据库中粗略分有三项内容：表、视图、存储过程。 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;数据库最基础的是表，表包括字段，字段包括主键、外键。如一个数据库有两个表：Users（用户表）、Article（文章）， Users包括主键UserID、用户姓名Name;Article表包括：文章主键ArticleID、文章标题Title、文章内容Content、外键文章所有人UserID。 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;当我们读取文章列表时希望能同时读取文章所有人的姓名即Users表中的Name字段，这时我们需要创建一个视图，以方便读取，视图的命名为：View+表名即ViewArticle。视图与表性质一样，只是在Article所有字段外添加了Name字段。 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;有几种对表数据进行操作的常规方法：添加一条记录(Add)、删除一条记录(Delete)、更新一条记录(Update)、读取一条记录(Load)、读取一个记录集(List)。我们应该养成所有对数据进行操作都在存储过程中进行的习惯，所以数据库中会有五种常规的存储过程。Add、 Update、Delete三种方法均直接对表进行操作，Load、List方法如果表有视图则在视图中读取否则也直接在表中读取。除了以上五类存储过程外还会有一些根据业务需要用户自定义的存储过程。 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;至此我们粗略了解了数据库的结构，那我们如何来创建对象？对象的创建应该以数据库中的表为基础，表中的字段具有对象属性的特性，所以我们将字段映射为对象的属性；数据库中的存储过程具有对象方法的特性所以我们将存储过程映射为对象中的方法。为了使程序结构更加清晰我们将属性与方法分开，为属性建立一个基类如：CuserBase，在这个类中保存所有Users表对应的字段属性，类名定义为：C+表名+Base；方法类命名为Cusers，名称规则为：C+表名，Cusers续承CusersBase类。如果对应的表有视图时怎么办呢？就如Article有视图ViewArticle时，我们为扩展的字段Name建立一个扩展类CArticleExtend，命名规则为：C+表名+Extend，这时续承关系为：Carticle续承 CArticleExtend类，CArticleBase续承CArticleExtend类。数据库与程序的对应关系如下图：&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/2.gif" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/2.gif" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/2.gif"></A> <BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;.NET对象中的方法与存储过程有一个小的差别，List读取列表的方法在对象中分为两个：GetDataSet——这一方法程序返回 DataSet对象、List——这一方法返回对象的集合，所以我们需要再创建一个对象集合类如：CarticleCollection，命名规则为：C +表名+Collection。对象中List方法通过一个循环读取记录集中的数据，你可以在逐条读过程中将记录内容修改为你需要的形式再绑定到控件上，当然你可以不用List方法，那样你就不用创建集合类。 <BR>四、Oracle数据库与SqlServer数据库结构的差异 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;.NET一样支持用户使用Oracle数据库，对.NET程序而言没有太大的区别，但Oracle与SqlServer数据库的结构与 SqlServer是有所区别的。Oracle有包的概念，所以可以将过程更加对象化，我们将所有针对一个表操作的存储过程放在同一个包里，以便维护的时候更加清晰。包包括：包头和包体，包头为包的定义，定义过程的名称及输入输出参数，包体是具体的过程，请注册包头与包体的定义部分必须对应否则将会出错。 Oracle与SqlServer的另一个差别是Oracle中自动生成的ID需要通过序列产生，不象SqlServer中设定字段为自动增长即可。在结构上主要区别就是有包的概念。&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/3.gif" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/3.gif" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/3.gif"></A> <BR>&nbsp; <BR>五、高效创建程序 <BR>&nbsp;&nbsp;&nbsp;&nbsp;有人会说这样的结构确实很清晰、易于维护，但开发时工作量会过大。现在向大家推荐一个代码生成的免费软件dbNet，他为你轻松生成四层中的两层：数据操作层和.NET对象层。这样可以将大量的时间节省下来，让你在效率和结构化双得。这一工具在http://www.dbo.cn中可以下载，有两个版本：SqlServer版和Oracle版。你可以将你的精力花在需求分析、数据结构设计和表示层的开发上，有很多人想到是否可以为你生成更多的代码，事实上是不可行的，因为机器永远不可能生成一个根据不同人不同需要的软件。六、dbNet软件介绍 <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;这一软件使用非常简单，先通过文件菜单连接数据库，之后软件会将你数据库中的表、视图、存储过程读取左侧的树中展示，如下图：&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/4.jpg" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/4.jpg" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/4.jpg"></A> <BR>&nbsp; <BR>右上方为生成代码窗口，右下方为属性窗口。有四种不同的代码分别生成：存储过程、基类、操作类、自定义函数。让我们逐个看看如何生成： <BR>存储过程生成： <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;点击左侧树中要生成存储过程的表，系统会自动读取这一表的字段，如果有视图会选中视图，你也可以更改视图，如下图：&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/5.jpg" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/5.jpg" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/5.jpg"></A> <BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;下方为表中的字段，只对ADD方法有效，打勾的字段为ADD方法输入字段，软件会自动筛选输入参数，有默认值的及自动生成的主键会自动不选。生成的方法也会先在数据库中查询是否已存在，如果已存在也不会选择，当然你也可以手动打勾。点击生成按钮更会生成所有选定的存储过程。基类生成： <BR>基类的生成非常简单，没有什么选项，可以根据程序的语言生成VB或C#。操作类生成： <BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;软件会自动设定每个类的名称，还会根据存储过程在数据库中是否存在选择生成的方法，如下图：&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/6.jpg" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/6.jpg" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/6.jpg"></A> <BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;如果方法与存储过程不对应你可以重新输入存储过程名称，点击生成操作类按钮即完成代码生成。请注册在生成存储过程并创建后请先刷新数据库，因为数据库已有更新。自定义函数生成： <BR>当我们除五种常规的存储过程外另外创建了存储过程时我们可以通过这里生成.NET代码。这里的操作请先点击要生成程序代码的存储过程，如下图：&nbsp; <BR><A href="http://fabu.beareyes.com.cn/2/lib/200510/08/242/7.jpg" target=_blank><IMG src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/7.jpg" border=0 ilo-full-src="http://fabu.beareyes.com.cn/2/lib/200510/08/242/7.jpg"></A> <BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;软件会查找相对应的表，这里的查找只有在命名规则与系统相同时才能找到，如果不能找到对应的表请手动选择，以及选择对应视图。生成的方法类型请选择一种类型，添加记录、删除记录、更新记录均为无返回值方法，加载一条记录请选Load,读取一个列表请选择List,点击生成按钮完成生成。&nbsp; </SPAN><img src ="http://www.cnitblog.com/sugar/aggbug/7511.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sugar/" target="_blank">sugar</a> 2006-03-12 13:53 <a href="http://www.cnitblog.com/sugar/archive/2006/03/12/7511.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>.NET中的正则表达式使用高级技巧 </title><link>http://www.cnitblog.com/sugar/archive/2006/03/03/7142.html</link><dc:creator>sugar</dc:creator><author>sugar</author><pubDate>Fri, 03 Mar 2006 09:23:00 GMT</pubDate><guid>http://www.cnitblog.com/sugar/archive/2006/03/03/7142.html</guid><wfw:comment>http://www.cnitblog.com/sugar/comments/7142.html</wfw:comment><comments>http://www.cnitblog.com/sugar/archive/2006/03/03/7142.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sugar/comments/commentRss/7142.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sugar/services/trackbacks/7142.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: .net中的正则表达式使用高级技巧     前言      一、本系列文章不讲述基本的正则语法，这些可以在微软的JS帮助文档中找到，也可以Google一下         二、写系列文章的原因         1、正则很有用，而且经常要用         2、正则的一些高级用法有相当一部分人还没有理解和掌握         3、刚好又在网上看到了一篇文章错误的使用了正则式，使我有了写本文的冲动  ...&nbsp;&nbsp;<a href='http://www.cnitblog.com/sugar/archive/2006/03/03/7142.html'>阅读全文</a><img src ="http://www.cnitblog.com/sugar/aggbug/7142.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sugar/" target="_blank">sugar</a> 2006-03-03 17:23 <a href="http://www.cnitblog.com/sugar/archive/2006/03/03/7142.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>整个站点默认禁用 Session，而某个页面不禁用的做法。</title><link>http://www.cnitblog.com/sugar/archive/2006/02/26/6975.html</link><dc:creator>sugar</dc:creator><author>sugar</author><pubDate>Sun, 26 Feb 2006 08:50:00 GMT</pubDate><guid>http://www.cnitblog.com/sugar/archive/2006/02/26/6975.html</guid><wfw:comment>http://www.cnitblog.com/sugar/comments/6975.html</wfw:comment><comments>http://www.cnitblog.com/sugar/archive/2006/02/26/6975.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sugar/comments/commentRss/6975.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sugar/services/trackbacks/6975.html</trackback:ping><description><![CDATA[<H3><A id=RecentPosts__ctl4_Hyperlink2 href="http://blog.joycode.com/ghj/archive/2006/02/23/71910.aspx" aiotitle="整个站点默认禁用 Session，而某个页面不禁用的做法。"></A>&nbsp;</H3>
<P>整个站点默认禁用 Session，而某个页面不禁用的做法。</P>
<P>先说一个不正确的做法：<BR>整个站点的 Web.config 被设置为：<BR>&lt;configuration&gt;<BR>&nbsp;&lt;system.web&gt;<BR>&nbsp; &lt;sessionState mode="Off"/&gt;<BR>&nbsp;&lt;/system.web&gt;<BR>&lt;/configuration&gt;<BR>在单独需要用Sesssion的页面，设置<BR>&lt;%@ Page&nbsp; EnableSessionState="True"%&gt;</P>
<P>这种做法是错误的，你会发现仍然是错误：</P>
<P>只有在配置文件或 Page 指令中将启用会话状态设置为真时，才可以使用会话状态 <BR>或者是：<BR>Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the &lt;configuration&gt;\&lt;system.web&gt;\&lt;httpModules&gt; section in the application configuration.</P>
<P>后面告诉原因。</P>
<P>正确的做法是<BR>Web.config 节sessionState 不要使用下面配置，<BR>&lt;sessionState mode="Off"/&gt;，<BR>而是用其他几种配置方式。（不设置的默认配置是 InProc。 ）</P>
<P>然后在在这个 Web.config 中设置<BR>&lt;configuration&gt;<BR>&nbsp;&lt;system.web&gt;<BR>&nbsp;&nbsp; &lt;pages enableSessionState="false" /&gt;<BR>&nbsp;&lt;/system.web&gt;<BR>&lt;/configuration&gt;</P>
<P>这样整个站点的页面默认是不打开Session的。<BR>在你需要的页面的 使用如下 Page 设置<BR>&lt;%@ Page EnableSessionState="True"%&gt;</P>
<P>或者在你需要打开Session的目录下，设置一个 web.config<BR>&lt;configuration&gt;<BR>&nbsp;&lt;system.web&gt;<BR>&nbsp;&nbsp; &lt;pages enableSessionState="true" /&gt;<BR>&nbsp;&lt;/system.web&gt;<BR>&lt;/configuration&gt;</P>
<P>&nbsp;</P>
<P>分析原因：<BR>&nbsp; &lt;sessionState mode="Off"/&gt;&nbsp; 是整个站点禁用了Session，你无法作特列处理。</P>
<P>另外，通过访问 System.Web.SessionState.HttpSessionState.Mode 属性的值，可以查看当前选定的会话状态。</P>
<P>上述知识点，不仅仅适用于 ASP.net 1.0 1.1 也适用于 2.0</P>
<P>资料：<BR>HOW TO：在 ASP.NET 中禁用 ASP 会话状态<BR><A href="http://support.microsoft.com/?scid=kb;zh-cn;306996&amp;spid=548&amp;sid=89">http://support.microsoft.com/?scid=kb;zh-cn;306996&amp;spid=548&amp;sid=89</A><BR><BR>&nbsp;摘自</P>
<H1><A class=headermaintitle id=Header1_HeaderTitle href="http://blog.joycode.com/ghj/"><FONT size=4>蝈蝈俊.net</FONT></A></H1><img src ="http://www.cnitblog.com/sugar/aggbug/6975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sugar/" target="_blank">sugar</a> 2006-02-26 16:50 <a href="http://www.cnitblog.com/sugar/archive/2006/02/26/6975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ADO.NET 的最佳实践技巧</title><link>http://www.cnitblog.com/sugar/archive/2006/02/21/6766.html</link><dc:creator>sugar</dc:creator><author>sugar</author><pubDate>Tue, 21 Feb 2006 02:01:00 GMT</pubDate><guid>http://www.cnitblog.com/sugar/archive/2006/02/21/6766.html</guid><wfw:comment>http://www.cnitblog.com/sugar/comments/6766.html</wfw:comment><comments>http://www.cnitblog.com/sugar/archive/2006/02/21/6766.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sugar/comments/commentRss/6766.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sugar/services/trackbacks/6766.html</trackback:ping><description><![CDATA[<h2>简介</h2><p>    本文为您提供了在 Microsoft ADO.NET 应用程序中实现和获得最佳性能、可伸缩性以及功能的最佳解决方案；同时也讲述了使用 ADO.NET 中可用对象的最佳实践；并提出一些有助于优化 ADO.NET 应用程序设计的建议。</p><p>    本文包含： </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    有关 .NET 框架包含的 .NET 框架数据提供程序的信息。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <b>DataSet</b> 和 <b>DataReader</b> 之间的比较，以及这些对象中每个对象最佳用法的解释。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    解释如何使用 <b>DataSet</b>、<b>Commands</b> 和 <b>Connections</b>。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    有关与 XML 集成的信息。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    通用的技巧和问题。                 </p>            </td>        </tr>    </tbody></table><a name="ENAA"></a> <h2>使用 DataReader、DataSet、DataAdapter 和 DataView</h2><p>    ADO.NET 提供以下两个对象，用于检索关系数据并将其存储在内存中：<b>DataSet</b> 和 <b>DataReader</b>。<b>DataSet</b> 提供一个内存中数据的关系表示形式，一整套包括一些表在内的数据（这些表包含数据、对数据进行排序并约束数据），以及表之间的关系。<b>DataReader</b> 提供一个来自数据库的快速、只进、只读数据流。 </p><p>    当使用 <b>DataSet</b> 时，经常会利用 <b>DataAdapter</b>（也可能是 <b>CommandBuilder</b>）与数据源进行交互。<span style="COLOR: #0000ff" twffan="done">当使用 <b>DataSet</b> 时，也可以利用 <b>DataView</b> 对 <b>DataSet</b> 中的数据应用排序和筛选。也可以从 <b>DataSet</b> 继承，创建强类型 <b>DataSet</b>，用于将表、行和列作为强类型对象属性公开</span>。 </p><p>    下列主题包括的信息涉及：使用 <b>DataSet</b> 或 <b>DataReader</b> 的最佳时机、如何优化访问它们所包含数据、以及如何优化使用 <b>DataAdapter</b>（包括 <b>CommandBuilder</b>）和 <b>DataView</b> 的技巧。 </p><p>    <b>DataSet 与 DataReader</b> </p><p>    当设计应用程序时，要考虑应用程序所需功能的等级，以确定使用 <b>DataSet</b> 或者是 <b>DataReader</b>。 </p><p>    要通过应用程序执行以下操作，就要使用 <b>DataSet</b>： </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    在结果的多个离散表之间进行导航。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    操作来自多个数据源（例如，来自多个数据库、一个 XML 文件和一个电子表格的混合数据）的数据。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    在各层之间交换数据或使用 XML Web 服务。与 <b>DataReader</b> 不同的是，<b>DataSet</b> 能传递给远程客户端。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    重用同样的行组，以便通过缓存获得性能改善（例如排序、搜索或筛选数据）。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    每行执行大量处理。对使用 <b>DataReader</b> 返回的每一行进行扩展处理会延长服务于 <b>DataReader</b> 的连接的必要时间，这影响了性能。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    使用 XML 操作对数据进行操作，例如可扩展样式表语言转换（XSLT 转换）或 XPath 查询。                 </p>            </td>        </tr>    </tbody></table><p>    对于下列情况，要在应用程序中使用 <b>DataReader</b>： </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    不需要缓存数据。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    要处理的结果集太大，内存中放不下。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    一旦需要以只进、只读方式快速访问数据。                 </p>            </td>        </tr>    </tbody></table><p>    <b>注</b>填充 <b>DataSet</b> 时，<b>DataAdapter</b> 使用 <b>DataReader</b>。因此，使用 <b>DataAdapter</b> 取代 <b>DataSet</b> 提升的性能表现为节省了 <b>DataSet</b> 占用内存和填充 <b>DataSet</b> 需要的循环。一般来说，此性能提升只是象征性的，因此，设计决策应以所需功能为基础。 </p><p>    <b>使用强类型 DataSet 的好处</b> </p><p>    <b>DataSet</b> 的另一个好处是可被继承以创建一个强类型 <b>DataSet</b>。强类型 <b>DataSet</b> 的好处包括设计时类型检查，以及 Microsoft Visual Studio .NET 用于强类型 <b>DataSet</b> 语句结束所带来的好处。修改了 <b>DataSet</b> 的架构或关系结构后，就可以创建一个强类型 <b>DataSet</b>，把行和列作为对象的属性公开，而不是作为集合中的项公开。例如，不公开客户表中行的姓名列，而公开 <b>Customer</b> 对象的 <b>Name</b> 属性。类型化 <b>DataSet</b> 从 <b>DataSet</b> 类派生，因此不会牺牲 <b>DataSet</b> 的任何功能。也就是说，类型化 <b>DataSet</b> 仍能远程访问，并作为数据绑定控件（例如 <b>DataGrid</b>）的数据源提供。<span style="COLOR: #0000ff" twffan="done">如果架构事先不可知，仍能受益于通用 <b>DataSet</b> 的功能，但却不能受益于强类型 <b>DataSet</b> 的附加功能</span>。 </p><p>    <b>处理强类型 DataSet 中的空引用</b> </p><p>    使用强类型 <b>DataSet</b> 时，可以批注 <b>DataSet</b> 的 XML 架构定义语言 (XSD) 架构，以确保强类型 <b>DataSet</b> 正确处理空引用。<span style="COLOR: #0000ff" twffan="done">nullValue 批注使您可用一个指定的值 String.Empty 代替 DBNull、保留空引用或引发异常</span>。选择哪个选项取决于应用程序的上下文。默认情况下，如果遇到空引用，就会引发异常。 </p><p>    有关更多信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconWorkingWithTypedDataSet.asp" target="_blank">Working with a Typed DataSet</a>。 </p><p>    <b>刷新 DataSet 中的数据</b> </p><p>    如果想用服务器上的更新值刷新 <b>DataSet</b> 中的值，就使用 <b>DataAdapter.Fill</b>。<span style="COLOR: #0000ff" twffan="done">如果有在 <b>DataTable</b> 上定义的主键，<b>DataAdapter.Fill</b> 会根据主键进行新行匹配，并且当更改到现有行时应用服务器上的值</span>。即使刷新之前修改了它们，刷新行的 <b>RowState</b> 仍被设置为 <b>Unchanged</b>。注意，如果没有为 <b>DataTable</b> 定义主键，<b>DataAdapter.Fill </b>就用可能重复的主键值添加新行。 </p><p>    如果想用来自服务器的当前值刷新表，并同时保留对表中的行所做的任何更改，必须首先用 <b>DataAdapter.Fill</b> 填充表，并填充一个新的 <b>DataTable</b>，然后用 <b>preserveChanges</b> 值 <b>true</b> 把 <b>DataTable</b><b>Merge</b> 到 <b>DataSet</b> 中。 </p><p>    <b>在 DataSet 中搜索数据</b> </p><p>    在 <b>DataSet</b> 中查询与特定条件相匹配的行时，可以利用基于索引的查找提高搜索性能。当把 <b>PrimaryKey</b> 值赋给 <b>DataTable</b> 时，会创建一个索引。当给 <b>DataTable</b> 创建 <b>DataView</b> 时，也会创建一个索引。下面是一些利用基于索引进行查找的技巧。 </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    如果对组成 <b>DataTable</b> 的 <b>PrimaryKey</b>的列进行查询，要使用 <b>DataTable.Rows.Find</b> 而不是 <b>DataTable.Select</b>。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    对于涉及到非主键列的查询，可以使用 <b>DataView</b> 为数据的多个查询提高性能。当把排序顺序应用到 <b>DataView</b> 时，就会建立一个搜索时使用的索引。<b>DataView</b> 公开 <b>Find</b> 和 <b>FindRows</b> 方法，以便查询基础 <b>DataTable</b> 中的数据。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    如果不需要表的排序视图，仍可以通过为 <b>DataTable</b> 创建 <b>DataView</b> 来利用基于索引的查找。注意，只有对数据执行多个查询操作时，这样才会带来好处。如果只执行单一查询，创建索引所需要的处理就会降低使用索引所带来的性能提升。                 </p>            </td>        </tr>    </tbody></table><p>    <b>DataView 构造</b> </p><p>    如果创建了 <b>DataView</b>，并且修改了 <b>Sort</b>、<b>RowFilter</b> 或 <b>RowStateFilter</b> 属性，<b>DataView</b> 就会为基础 <b>DataTable</b> 中的数据建立索引。创建 <b>DataView</b> 对象时，要使用 <b>DataView</b> 构造函数，它用 <b>Sort</b>、<b>RowFilter</b> 和 <b>RowStateFilter</b> 值作为构造函数参数（与基础 <b>DataTable</b> 一起）。结果是创建了一次索引。创建一个“空”<b>DataView</b> 并随后设置 <b>Sort</b>、<b>RowFilter</b> 或 <b>RowStateFilter</b> 属性，会导致索引至少创建两次。 </p><p>    <b>分页</b> </p><p>    ADO.NET 可以显式控制从数据源中返回什么样的数据，以及在 <b>DataSet</b> 中本地缓存多少数据。对查询结果的分页没有唯一的答案，但下面有一些设计应用程序时应该考虑的技巧。 </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">避免使用带有 <b>startRecord</b> 和 <b>maxRecords</b> 值的 <b>DataAdapter.Fill </b>重载</span>。当以这种方式填充 <b>DataSet</b> 时，只有 <b>maxRecords</b> 参数（从 <b>startRecord</b> 参数标识的记录开始）指定的记录数量用于填充 <b>DataSet</b>，但无论如何总是返回完整的查询。这就会引起不必要的处理，用于读取“不需要的”记录；而且为了返回附加记录，会耗尽不必要的服务器资源。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">用于每次只返回一页记录的技术是创建 SQL 语句，把 WHERE 子句以及 ORDER BY 子句和 TOP 谓词组合起来</span>。此技术取决于存在一种可唯一标识每一行的办法。当浏览下一页记录时，修改 WHERE 子句使之包含所有唯一标识符大于当前页最后一个唯一标识符的记录。当浏览上一页记录时，修改 WHERE 子句使之返回所有唯一标识符小于当前页第一个唯一标识符的记录。<u>两种查询都只返回记录的 TOP 页</u>。当浏览上一页时，需要以降序为结果排序。这将有效地返回查询的最后一页（如果需要，显示之前也许要重新排序结果）。有关这个技术的一个示例，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconPagingThroughQueryResult.asp" target="_blank">Paging Through a Query Result</a>。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    另一项每次只返回一页记录的技术是创建 SQL 语句，把 TOP 谓词和嵌入式 SELECT 语句的使用结合在一起。此技术并不依赖于存在一种可唯一标识每一行的办法。使用这项技术的第一步是把所需页的数量与页大小相乘。然后将结果传递给 SQL Query 的 TOP 谓词，该查询以升序排列。再把此查询嵌入到另一个查询中，后者从降序排列的嵌入式查询结果中选择 TOP 页大小。实质上，返回的是嵌入式查询的最后一页。例如，要返回查询结果的第三页（页大小是 10），应该书写如下所示的命令：                 </p>                <pre class="codeSample">SELECT TOP 10 * FROM  (SELECT TOP 30 * FROM Customers ORDER BY Id ASC) AS Table1ORDER BY Id DESC</pre>                <p>                    注意，从查询中返回的结果页以降序显示。如果需要，应该重新排序。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">如果数据不经常变动，可以在 <b>DataSet</b> 中本地维护一个记录缓存，以此提高性能</span>。例如，可以在本地 <b>DataSet</b> 中存储 10 页有用的数据，并且只有当用户浏览超出缓存第一页和最后一页时，才从数据源中查询新数据。                 </p>            </td>        </tr>    </tbody></table><p>    有关更多信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/dnbda/html/daag.asp" target="_blank">.NET Data Access Architecture Guide</a>。 </p><p>    <b>用架构填充 DataSet</b> </p><p>    当用数据填充 <b>DataSet</b> 时，<b>DataAdapter.Fill </b>方法使用 <b>DataSet</b> 的现有架构，并使用从 <b>SelectCommand</b> 返回的数据填充它。如果在 <b>DataSet</b> 中没有表名与要被填充的表名相匹配，<b>Fill</b> 方法就会创建一个表。默认情况下，<b>Fill</b> 仅定义列和列类型。 </p><p>    通过设置 <b>DataAdapter</b> 的 <b>MissingSchemaAction</b> 属性，可以重写 <b>Fill</b> 的默认行为。例如，要让 <b>Fill</b> 创建一个表架构，并且还包括主键信息、唯一约束、列属性、是否允许为空、最大列长度、只读列和自动增量的列，就要把 <b>DataAdapter.MissingSchemaAction</b> 指定为 <b>MissingSchemaAction.AddWithKey</b>。或者，在调用 <b>DataAdapter.Fill</b> 前，可以调用 <b>DataAdapter.FillSchema</b> 来确保当填充 <b>DataSet</b> 时架构已到位。 </p><p>    对 <b>FillSchema</b> 的调用会产生一个到服务器的额外行程，用于检索附加架构信息。为了获得最佳性能，需要在调用 <b>Fill</b> 之前指定 <b>DataSet</b> 的架构，或者设置 <b>DataAdapter</b> 的 <b>MissingSchemaAction</b>。 </p><p>    <b>使用 CommandBuilder 的最佳实践</b> </p><p>    假设 <b>SelectCommand</b> 执行单一表 SELECT，<b>CommandBuilder</b> 就会以 <b>DataAdapter</b> 的 <b>SelectCommand</b> 属性为基础自动生成 <b>DataAdapter</b> 的 <b>InsertCommand</b>、<b>UpdateCommand</b>、和 <b>DeleteCommand</b> 属性。下面是为获得最佳性能而使用 <b>CommandBuilder</b> 的一些技巧。 </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <b>CommandBuilder</b> 的使用应该限制在设计时或即席方案中。生成 <b>DataAdapter</b> 命令属性所必需的处理会影响性能。如果预先知道 INSERT/UPDATE/DELETE 语句的内容，就显式设置它们。一个比较好的设计技巧是，为 INSERT/UPDATE/DELETE 命令创建存储过程并显式配置 <b>DataAdapter</b> 命令属性以使用它们。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <b>CommandBuilder</b> 使用 <b>DataAdapter</b> 的 <b>SelectCommand</b> 属性确定其他命令属性的值。如果 <b>DataAdapter</b> 的 <b>SelectCommand</b> 本身曾经更改过，确保调用 <b>RefreshSchema</b> 以更新命令属性。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    如果 <b>DataAdapter</b> 命令属性为空（命令属性默认情况下为空），<b>CommandBuilder</b> 仅仅为它生成一条命令。如果显式设置了命令属性，<b>CommandBuilder</b> 不会重写它。如果希望 <b>CommandBuilder</b> 为以前已经设置过的命令属性生成命令，就把命令属性设置为空。                 </p>            </td>        </tr>    </tbody></table><p>    <b>批处理 SQL 语句</b> </p><p>    很多数据库支持把多条命令合并或批处理成一条单一命令执行。例如，<span style="COLOR: #0000ff" twffan="done">SQL Server 使您可以用分号 (;) 分隔命令。把多条命令合并成单一命令，能减少到服务器的行程数，并提高应用程序的性能</span>。例如，可以把所有预定的删除在应用程序中本地存储起来，然后再发出一条批处理命令调用，从数据源删除它们。 </p><p>    虽然这样做确实能提高性能，但是，当对 <b>DataSet</b> 中的数据更新进行管理时，可能会增加应用程序的复杂性。要保持简单，可能要在 <b>DataSet</b> 中为每个 <b>DataTable</b> 创建一个 <b>DataAdapter</b>。 </p><p>    <b>用多个表填充 DataSet</b> </p><p>    如果使用批处理 SQL 语句检索多个表并填充 <b>DataSet</b>，第一个表用指定给 <b>Fill</b> 方法的表名命名。后面的表用指定给 <b>Fill</b> 方法的表名加上一个从 1 开始并且增量为 1 的数字命名。例如，如果运行下面的代码： </p><pre class="codeSample">'Visual BasicDim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection)Dim ds As DataSet = New DataSet()da.Fill(ds, "Customers")//C#SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection);DataSet ds = new DataSet();da.Fill(ds, "Customers");</pre><p>    来自 Customers 表的数据放在名为 "Customers" 的 <b>DataTable</b> 中。来自 Orders 表的数据放在名为 "Customers1" 的 <b>DataTable</b> 中。 </p><p>    填充完 <b>DataSet</b> 之后，可以很容易地把 "Customers1" 表的 <b>TableName</b> 属性改为 "Orders"。但是，后面的填充会导致 "Customers" 表被重新填充，而 "Orders" 表会被忽略，并创建另外一个 "Customers1" 表。为了对这种情况作出补救，创建一个 <b>DataTableMapping</b>，把 "Customers1" 映射到 "Orders"，并为其他后面的表创建其他的表映射。例如： </p><pre class="codeSample">'Visual BasicDim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection)da.TableMappings.Add("Customers1", "Orders")Dim ds As DataSet = New DataSet()da.Fill(ds, "Customers")//C#SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers; SELECT * FROM Orders;", myConnection);da.TableMappings.Add("Customers1", "Orders");DataSet ds = new DataSet();da.Fill(ds, "Customers");</pre><p>    <b>使用 DataReader</b> </p><p>    下面是一些使用 <b>DataReader</b> 获得最佳性能的技巧，同时还回答了一些关于使用 <b>DataReader</b> 的常见问题。 </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    在访问相关 <b>Command</b> 的任何输出参数之前，必须关闭 <b>DataReader</b>。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">完成读数据之后总是要关闭 <b>DataReader</b></span>。如果使用 <b>Connection</b> 只是用于返回 <b>DataReader</b>，那么关闭 <b>DataReader</b> 之后立刻关闭它。                 </p>                <p>                    另外一个显式关闭 <b>Connection</b> 的方法是把 <b>CommandBehavior.CloseConnection</b> 传递给 <b>ExecuteReader</b> 方法，以确保相关的连接在关闭 <b>DataReader</b> 时被关闭。如果从一个方法返回 <b>DataReader</b>，而且不能控制 <b>DataReader</b> 或相关连接的关闭，则这样做特别有用。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">不能在层之间远程访问 <b>DataReader</b></span>。<b>DataReader</b> 是为已连接好的数据访问设计的。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">当访问列数据时，使用类型化访问器，例如，<b>GetString</b>、<b>GetInt32</b> 等</span>。这使您不用进行将 <b>GetValue</b> 返回的 <b>Object</b> 强制转换成特定类型所需的处理。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">一个单一连接每次只能打开一个 <b>DataReader</b></span>。在 ADO 中，如果打开一个单一连接，并且请求两个使用只进、只读游标的记录集，那么 ADO 会在游标生存期内隐式打开第二个、未池化的到数据存储区的连接，然后再隐式关闭该连接。对于 ADO.NET，“秘密”完成的动作很少。如果想在相同的数据存储区上同时打开两个 <b>DataReaders</b>，就必须显式创建两个连接，每个 <b>DataReader</b> 一个。这是 ADO.NET 为池化连接的使用提供更多控制的一种方法。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">默认情况下，<b>DataReader</b> 每次 <b>Read</b> 时都要把整行加载到内存</span>。这允许在当前行内随机访问列。如果不需要这种随机访问，为了提高性能，就把 <b>CommandBehavior.SequentialAccess</b> 传递给 <b>ExecuteReader</b> 调用。这将 <b>DataReader</b> 的默认行为更改为仅在请求时将数据加载到内存。注意，<b>CommandBehavior.SequentialAccess </b>要求顺序访问返回的列。也就是说，一旦读过返回的列，就不能再读它的值了。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    如果已经完成读取来自 <b>DataReader</b> 的数据，但仍然有大量挂起的未读结果，就在调用 <b>DataReader</b> 的 <b>Close</b> 之前先调用 <b>Command</b> 的 <b>Cancel</b>。调用 <b>DataReader</b> 的 <b>Close</b> 会导致在关闭游标之前检索挂起的结果并清空流。调用 <b>Command</b> 的 <b>Cancel</b> 会放弃服务器上的结果，这样，<b>DataReader</b> 在关闭的时候就不必读这些结果。如果要从 <b>Command</b> 返回输出参数，还要调用 <b>Cancel</b> 放弃它们。如果需要读取任何输出参数，不要调用 <b>Command</b> 的 <b>Cancel</b>，只要调用 <b>DataReader</b> 的 <b>Close</b> 即可。                 </p>            </td>        </tr>    </tbody></table><p>    <b>二进制大对象 (BLOB)</b> </p><p>    <span style="COLOR: #0000ff" twffan="done">用 <b>DataReader</b> 检索二进制大对象 (BLOB) 时，应该把 <b>CommandBehavior.SequentialAccess</b> 传递给 <b>ExecuteReader</b> 方法调用</span>。因为 <b>DataReader</b> 的默认行为是每次 <b>Read</b> 都把整行加载到内存，又因为 BLOB 值可能非常大，所以结果可能由于单个 BLOB 而使大量内存被用光。<b>SequentialAccess</b> 将 <b>DataReader</b> 的行为设置为只加载请求的数据。然后还可以使用 <b>GetBytes</b> 或 <b>GetChars</b> 控制每次加载多少数据。 </p><p>    记住，使用 <b>SequentialAccess</b> 时，不能不按顺序访问 <b>DataReader</b> 返回的不同字段。也就是说，如果查询返回三列，其中第三列是 BLOB，并且想访问前两列中的数据，就必须在访问 BLOB 数据之前先访问第一列的值，然后访问第二列的值。这是因为现在数据是顺序返回的，并且 <b>DataReader</b> 一旦读过该数据，该数据就不再可用。 </p><p>    有关如何在 ADO.NET 中访问 BLOB 的详细描述，请参阅 <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconobtainingblobvaluesfromdatabase.asp" target="_blank">Obtaining BLOB Values from a Database</a>。 </p><div style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px" twffan="done"><a href="http://ltp.cnblogs.com/admin/#top"><img height="9" alt="返回页首" src="/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width="7" border="0" twffan="done"/></a><a class="topOfPage" href="/admin/#top">返回页首</a> </div><a name="EMAA"></a> <h2>使用命令</h2><p>    ADO.NET 提供了几种命令执行的不同方法以及优化命令执行的不同选项。下面包括一些技巧，它们是关于选择最佳命令执行以及如何提高执行命令的性能。</p><p>    <b>使用 OleDbCommand 的最佳实践</b> </p><p>    不同 .NET 框架数据提供程序之间的命令执行被尽可能标准化了。但是，数据提供程序之间仍然存在差异。下面给出一些技巧，可微调用于 OLE DB 的 .NET 框架数据提供程序的命令执行。 </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    按照 ODBC CALL 语法使用 <b>CommandType.Text</b> 调用存储过程。使用 <b>CommandType.StoredProcedure</b> 只是秘密地生成 ODBC CALL 语法。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <span style="COLOR: #0000ff" twffan="done">一定要设置 <b>OleDbParameter</b> 的类型、大小（如果适用）、以及精度和范围（如果参数类型是 numeric 或 decimal）</span><u>。</u>注意，如果不显式提供参数信息，<b>OleDbCommand</b> 会为每个执行命令重新创建 OLE DB 参数访问器。                 </p>            </td>        </tr>    </tbody></table><p>    <b>使用 SqlCommand 的最佳实践</b> </p><p>    使用 <b>SqlCommand</b> 执行存储过程的快速提示：<span style="COLOR: #0000ff" twffan="done">如果调用存储过程，将 <b>SqlCommand</b> 的 <b>CommandType</b> 属性指定为 <b>StoredProcedure</b> 的 <b>CommandType</b>。这样通过将该命令显式标识为存储过程，就不需要在执行之前分析命令</span>。 </p><p>    <b>使用 Prepare 方法</b> </p><p>    <span style="COLOR: #0000ff" twffan="done">对于重复作用于数据源的参数化命令，<b>Command.Prepare </b>方法能提高性能</span>。<b>Prepare</b> 指示数据源为多次调用优化指定的命令。要想有效利用 <b>Prepare</b>，需要彻底理解数据源是如何响应 <b>Prepare</b> 调用的。对于一些数据源（例如 SQL Server 2000），命令是隐式优化的，不必调用 <b>Prepare</b>。对于其他（例如 SQL Server 7.0）数据源，<b>Prepare</b> 会比较有效。 </p><p>    <b>显式指定架构和元数据</b> </p><p>    只要用户没有指定元数据信息，ADO.NET 的许多对象就会推断元数据信息。下面是一些示例： </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <b>DataAdapter.Fill </b>方法，如果 <b>DataSet</b> 中没有表和列，<b>DataAdapter.Fill </b>方法会在 <b>DataSet</b> 中创建表和列。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <b>CommandBuilder</b>，它会为单表 SELECT 命令生成 <b>DataAdapter</b> 命令属性。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    <b>CommandBuilder.DeriveParameters</b>，它会填充 <b>Command</b> 对象的 <b>Parameters</b> 集合。                 </p>            </td>        </tr>    </tbody></table><p>    但是，每次用到这些特性，都会有性能损失。建议将这些特性主要用于设计时和即席应用程序中。在可能的情况下，显式指定架构和元数据。其中包括在 <b>DataSet</b> 中定义表和列、定义 <b>DataAdapter</b> 的 <b>Command</b> 属性、以及为 <b>Command</b> 定义 <b>Parameter</b> 信息。 </p><p>    <b>ExecuteScalar 和 ExecuteNonQuery</b> </p><p>    <span style="COLOR: #0000ff" twffan="done">如果想返回像 Count(*)、Sum(Price) 或 Avg(Quantity) 的结果那样的单值，可以使用 <b>Command.ExecuteScalar</b>。<b>ExecuteScalar</b> 返回第一行第一列的值，将结果集作为标量值返回</span>。因为单独一步就能完成，所以 <b>ExecuteScalar</b> 不仅简化了代码，还提高了性能；要是使用 <b>DataReader</b> 就需要两步才能完成（即，<b>ExecuteReader</b> + 取值）。 </p><p>    使用不返回行的 SQL 语句时，例如修改数据（例如INSERT、UPDATE 或 DELETE）或仅返回输出参数或返回值，请使用 <b>ExecuteNonQuery</b>。这避免了用于创建空 <b>DataReader</b> 的任何不必要处理。 </p><p>    有关更多信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=gttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconadonetcommands.asp" target="_blank">Executing a Command</a>。 </p><p>    <b>测试 Null</b> </p><p>    如果表（在数据库中）中的列允许为空，就不能测试参数值是否“等于”空。相反，需要写一个 WHERE 子句，测试列和参数是否都为空。下面的 SQL 语句返回一些行，它们的 LastName 列等于赋给 @LastName 参数的值，或者 LastName 列和 @LastName 参数都为空。</p><pre class="codeSample">SELECT * FROM CustomersWHERE ((LastName = @LastName) OR (LastName IS NULL AND @LastName IS NULL))</pre><p>    <b>把 Null 作为参数值传递</b> </p><p>    对数据库的命令中，<span style="COLOR: #0000ff" twffan="done">当把空值作为参数值发送时，不能使用 <b>null</b>（Visual Basic庐 .NET 中为 <b>Nothing</b>）。而需要使用 <b>DBNull.Value</b></span>。例如： </p><pre class="codeSample">'Visual BasicDim param As SqlParameter = New SqlParameter("@Name", SqlDbType.NVarChar, 20)param.Value = DBNull.Value//C#SqlParameter param = new SqlParameter("@Name", SqlDbType.NVarChar, 20);param.Value = DBNull.Value;</pre><p>    <b>执行事务</b> </p><p>    ADO.NET 的事务模型已经更改。在 ADO 中，当调用 <b>StartTransaction</b> 时，调用之后的任何更新操作都被视为是事务的一部分。但是，在 ADO.NET 中，当调用 <b>Connection.BeginTransaction</b> 时，会返回一个 <b>Transaction</b> 对象，需要把它与 <b>Command</b> 的 <b>Transaction</b> 属性联系起来。这种设计可以在一个单一连接上执行多个根事务。如果未将 <b>Command.Transaction</b> 属性设置为一个针对相关的 <b>Connection</b> 而启动的 <b>Transaction</b>，那么 <b>Command</b> 就会失败并引发异常。 </p><p>    即将发布的 .NET 框架将使您可以在现有的分布式事务中手动登记。这对于对象池方案来说很理想；在该方案中，一个池对象打开一次连接，但是在多个独立的事务中都涉及到该对象。.NET 框架 1.0 发行版中这一功能并不可用。</p><p>    有关事务的更多信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconPerformingTransactions.asp" target="_blank">Performing Transactions</a> 以及 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/dnbda/html/daag.asp" target="_blank">.NET Data Access Architecture Guide</a>。 </p><div style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px" twffan="done"><a href="http://ltp.cnblogs.com/admin/#top"><img height="9" alt="返回页首" src="/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width="7" border="0" twffan="done"/></a><a class="topOfPage" href="/admin/#top">返回页首</a> </div><a name="ELAA"></a> <h2>使用连接</h2><p>    高性能应用程序与使用中的数据源保持最短时间的连接，并且利用性能增强技术，例如连接池。下面的主题提供一些技巧，有助于在使用 ADO.NET 连接到数据源时获得更好的性能。</p><p>    <b>连接池</b> </p><p>    用于 ODBC 的 SQL Server、OLE DB 和 .NET 框架数据提供程序隐式缓冲连接。通过在连接字符串中指定不同的属性值，可以控制连接池的行为。有关如何控制连接池的行为的详细信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconConnectionPoolingForSQLServerNETDataProvider.asp" target="_blank">Connection Pooling for the SQL Server .NET Data Provider</a> 和 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconConnectionPoolingForOLEDBNETDataProvider.asp" target="_blank">Connection Pooling for the OLE DB .NET Data Provider</a>。 </p><p>    <b>用 DataAdapter 优化连接</b> </p><p>    <b>DataAdapter</b> 的 <b>Fill</b> 和 <b>Update</b> 方法在连接关闭的情况下自动打开为相关命令属性指定的连接。如果 <b>Fill</b> 或 <b>Update</b> 方法打开了连接，<b>Fill</b> 或 <b>Update</b> 将在操作完成的时候关闭它。<span style="COLOR: #0000ff" twffan="done">为了获得最佳性能，仅在需要时将与数据库的连接保持为打开。同时，减少打开和关闭多操作连接的次数</span>。 </p><p>    如果只执行单个的 <b>Fill</b> 或 <b>Update</b> 方法调用，建议允许 <b>Fill</b> 或 <b>Update</b> 方法隐式打开和关闭连接。如果对 <b>Fill</b> 和/或 <b>Update</b> 调用有很多，建议显式打开连接，调用 <b>Fill</b> 和/或 <b>Update</b>，然后显式关闭连接。 </p><p>    另外，<span style="COLOR: #0000ff" twffan="done">当执行事务时，显式地在开始事务之前打开连接，并在提交之后关闭连接</span>。例如： </p><pre class="codeSample">'Visual BasicPublic Sub RunSqlTransaction(da As SqlDataAdapter, myConnection As SqlConnection, ds As DataSet)  myConnection.Open()  Dim myTrans As SqlTransaction = myConnection.BeginTransaction()  myCommand.Transaction = myTrans  Try    da.Update(ds)    myTrans.Commit()    Console.WriteLine("Update successful.")  Catch e As Exception    Try      myTrans.Rollback()    Catch ex As SqlException      If Not myTrans.Connection Is Nothing Then        Console.WriteLine("An exception of type " &amp; ex.GetType().ToString() &amp; _                          " was encountered while attempting to roll back the transaction.")      End If    End Try    Console.WriteLine("An exception of type " &amp; e.GetType().ToString() &amp; " was encountered.")    Console.WriteLine("Update failed.")  End Try  myConnection.Close()End Sub//C#public void RunSqlTransaction(SqlDataAdapter da, SqlConnection myConnection, DataSet ds){  myConnection.Open();  SqlTransaction myTrans = myConnection.BeginTransaction();  myCommand.Transaction = myTrans;  try  {    da.Update(ds);    myCommand.Transaction.Commit();    Console.WriteLine("Update successful.");  }  catch(Exception e)  {    try    {      myTrans.Rollback();    }    catch (SqlException ex)    {      if (myTrans.Connection != null)      {        Console.WriteLine("An exception of type " + ex.GetType() +                          " was encountered while attempting to roll back the transaction.");      }    }    Console.WriteLine(e.ToString());    Console.WriteLine("Update failed.");  }  myConnection.Close();}</pre><p>    <b>始终关闭 Connection 和 DataReader</b> </p><p>    <span style="COLOR: #0000ff" twffan="done">完成对 <b>Connection</b> 或 <b>DataReader</b> 对象的使用后，总是显式地关闭它们</span>。尽管垃圾回收最终会清除对象并因此释放连接和其他托管资源，但垃圾回收仅在需要时执行。因此，确保任何宝贵的资源被显式释放仍然是您的责任。并且，没有显式关闭的 <b>Connections</b> 可能不会返回到池中。例如，<span style="COLOR: #0000ff" twffan="done">一个超出作用范围却没有显式关闭的连接，只有当池大小达到最大并且连接仍然有效时，才会被返回到连接池中</span>。 </p><p>    <b>注</b> <span style="COLOR: #0000ff" twffan="done">不要在类的 <b>Finalize</b> 方法中对 <b>Connection</b>、<b>DataReader</b> 或任何其他托管对象调用 <b>Close</b> 或 <b>Dispose</b>。最后完成的时候，仅释放类自己直接拥有的非托管资源。如果类没有任何非托管资源，就不要在类定义中包含 <b>Finalize</b> 方法</span>。 </p><p>    <b>在 C# 中使用 "Using" 语句</b> </p><p>    对于 C# 程序员来说，<span style="COLOR: #0000ff" twffan="done">确保始终关闭 <b>Connection</b> 和 <b>DataReader</b> 对象的一个方便的方法就是使用 <b>using</b> 语句。<b>using</b> 语句在离开自己的作用范围时，会自动调用被“使用”的对象的 <b>Dispose</b></span>。例如： </p><pre class="codeSample">//C#string connString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;";using (SqlConnection conn = new SqlConnection(connString)){  SqlCommand cmd = conn.CreateCommand();  cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";    conn.Open();  using (SqlDataReader dr = cmd.ExecuteReader())  {    while (dr.Read())      Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));  }}</pre><p>    Using 语句不能用于 Microsoft庐 Visual Basic庐 .NET。</p><p>    <b>避免访问 OleDbConnection.State 属性</b> </p><p>    如果连接已经打开，<b>OleDbConnection.State</b> 属性会对 <b>DBPROP_CONNECTIONSTATUS</b> 属性的 <b>DATASOURCEINFO </b>属性集执行本地 OLE DB 调用 <b>IDBProperties.GetProperties</b>，这可能会导致对数据源的往返行程。也就是说，<span style="COLOR: #0000ff" twffan="done">检查 <b>State</b> 属性的代价可能很高。所以仅在需要时检查 <b>State</b> 属性</span>。如果需要经常检查该属性，监听 <b>OleDbConnection</b> 的 <b>StateChange</b> 事件可能会使应用程序的性能好一些。有关 <b>StateChange</b> 事件的详细信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconWorkingWithConnectionEvents.asp" target="_blank">Working with Connection Events</a>。 </p><div style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px" twffan="done"><a href="http://ltp.cnblogs.com/admin/#top"><img height="9" alt="返回页首" src="/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width="7" border="0" twffan="done"/></a><a class="topOfPage" href="/admin/#top">返回页首</a> </div><a name="EKAA"></a> <h2>与 XML 集成</h2><p>    ADO.NET 在 <b>DataSet</b> 中提供了广泛的 XML 集成，并公开了 SQL Server 2000 及其更高版本提供的部分 XML 功能。还可以使用 SQLXML 3.0 广泛地访问 SQL Server 2000 及其更高版本中的 XML 功能。下面是使用 XML 和 ADO.NET 的技巧和信息。 </p><p>    <b>DataSet 和 XML</b> </p><p>    <b>DataSet</b> 与 XML 紧密集成，并提供如下功能： </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    从 XSD 架构中加载 <b>DataSet</b> 的架构或关系型结构。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    从 XML 加载 <b>DataSet</b> 的内容。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    如果没有提供架构，可以从 XML 文档的内容推断出 <b>DataSet</b> 的架构。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    把 <b>DataSet</b> 的架构写成 XSD 架构。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    把 <b>DataSet</b> 的内容写成 XML。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    同步访问使用 <b>DataSet</b> 的数据的关系表示，以及使用 <b>XmlDataDocument</b> 的数据的层次表示。                 </p>            </td>        </tr>    </tbody></table><p>    <b>注</b> 可以使用这种同步把 XML 功能（例如，XPath 查询和 XSLT 转换）应用到 <b>DataSet</b> 中的数据，或者在保留原始 XML 保真度的前提下为 XML 文档中数据的全部或其中一个子集提供关系视图。 </p><p>    关于 <b>DataSet</b> 提供的 XML 功能的详细信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconXMLDataSet.asp" target="_blank">XML and the DataSet</a>。 </p><p>    <b>架构推断</b> </p><p>    从 XML 文件加载 <b>DataSet</b> 时，可以从 XSD 架构加载 <b>DataSet</b> 架构，或者在加载数据前预定义表和列。如果没有可用的 XSD 架构，而且不知道为 XML 文件的内容定义哪些表和列，就可以在 XML 文档结构的基础上对架构进行推断。 </p><p>    架构推断作为迁移工具很有用，但应只限于设计阶段应用程序，这是由于推断处理有如下限制。 </p><table cellspacing="0" cellpadding="0" border="0">    <tbody>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    对架构的推断会引入影响应用程序性能的附加处理。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    所有推断列的类型都是字符串。                 </p>            </td>        </tr>        <tr>            <td class="listBullet" valign="top">                •</td>            <td class="listItem">                <p>                    推断处理不具有确定性。也就是说，它是基于 XML 文件内容的，而不是预定的架构。因此，对于两个预定架构相同的 XML 文件，由于它们的内容不同，结果得到两个完全不同的推断架构。                 </p>            </td>        </tr>    </tbody></table><p>    有关更多信息，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconInferringDataSetRelationalStructureFromXML.asp" target="_blank">Inferring DataSet Relational Structure from XML</a>。 </p><p>    <b>用于 XML 查询的 SQL Server</b> </p><p>    如果正从 SQL Server 2000 FOR XML 返回查询结果，可以让用于 SQL Server 的 .NET 框架数据提供程序使用 <b>SqlCommand.ExecuteXmlReader</b> 方法直接创建一个 <b>XmlReader</b>。 </p><p>    <b>SQLXML 托管类</b> </p><p>    .NET 框架中有一些类，公开用于 SQL Server 2000 的 XML 的功能。这些类可在 <b>Microsoft.Data.SqlXml </b>命名空间中找到，它们添加了执行 XPath 查询和 XML 模板文件以及把 XSLT 转换应用到数据的能力。 </p><p>    SQLXML 托管类包含在用于 Microsoft SQL Server 2000 的 XML (SQLXML 2.0) 发行版中，可从 <a href="http://www.microsoft.com/downloads/release.asp?ReleaseID=33055" target="_blank">XML for Microsoft SQL Server 2000 Web Release 2 (SQLXML 2.0)</a> ??μ?。 </p><div style="MARGIN-TOP: 3px; MARGIN-BOTTOM: 10px" twffan="done"><a href="http://ltp.cnblogs.com/admin/#top"><img height="9" alt="返回页首" src="/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif" width="7" border="0" twffan="done"/></a><a class="topOfPage" href="/admin/#top">返回页首</a> </div><a name="EJAA"></a> <h2>更多有用的技巧</h2><p>    下面是一些编写 ADO.NET 代码时的通用技巧。</p><p>    <b>避免自动增量值冲突</b> </p><p>    就像大多数数据源一样，<b>DataSet</b> 使您可标识那些添加新行时自动对其值进行递增的列。在 <b>DataSet</b> 中使用自动增量的列时，如果自动增量的列来自数据源，可避免添加到 <b>DataSet</b> 的行和添加到数据源的行之间本地编号冲突。 </p><p>    例如，考虑一个表，它的主键列 CustomerID 是自动增量的。两个新的客户信息行添加到表中，并接收到自动增量的 CustomerID 值 1 和 2。然后，只有第二个客户行被传递给 <b>DataAdapter</b> 的方法 <b>Update</b>，新添加的行在数据源接收到一个自动增量的 CustomerID 值 1，与 <b>DataSet</b> 中的值 2 不匹配。当 <b>DataAdapter</b> 用返回值填充表中第二行时，就会出现约束冲突，因为第一个客户行已经使用了 CustomerID 值 1。 </p><p>    要避免这种情况，建议在使用数据源上自动增量的列以及 <b>DataSet</b> 上自动增量的列时，把 <b>DataSet</b> 中的列创建为 <b>AutoIncrementStep</b> 值等于 -1 并且 <b>AutoIncrementSeed</b> 值等于 0，另外，还要确保数据源生成的自动增量标识值从 1 开始，并且以正阶值递增。因此，<b>DataSet</b> 为自动增量值生成负数，与数据源生成的正自动增量值不冲突。另外一个选择是使用 <b>Guid</b> 类型的列，而不是自动增量的列。生成 <b>Guid</b> 值的算法应该永远不会使数据源中生成的 <b>Guid</b> 值与 <b>DataSet</b> 中生成的 <b>Guid</b> 值一样。 </p><p>    如果自动增量的列只是用作唯一值，而且没有任何意义，就考虑使用 Guid 代替自动增量的列。它们是唯一的，并且避免了使用自动增量的列所必需的额外工作。</p><p>    有关从数据源检索自动增量的列值的示例，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconRetrievingIdentityOrAutonumberValues.asp" target="_blank">Retrieving Identity or AutoNumber Values</a>。 </p><p>    <b>检查开放式并发冲突</b> </p><p>    按照设计，由于 <b>DataSet</b> 是与数据源断开的，所以，当多个客户端在数据源上按照开放式并发模型更新数据时，需要确保应用程序避免冲突。 </p><p>    在测试开放式并发冲突时有几项技术。一项技术涉及在表中包含时间戳列。另外一项技术是，验证一行中所有列的原始值是否仍然与通过在 SQL 语句中使用 WHERE 子句进行测试时在数据库中找到的值相匹配。</p><p>    有关包含代码示例的该主题的详细讨论，请参阅 <a href="http://msdn.microsoft.com/default.aspx?pull=/library/en-us/cpguide/html/cpconOptimisticConcurrency.asp" target="_blank">Optimistic Concurrency</a>。 </p><p>    <b>多线程编程</b> </p><p>    ADO.NET 对性能、吞吐量和可伸缩性进行优化。因此，<span style="COLOR: #0000ff" twffan="done">ADO.NET 对象不锁定资源，并且必须只用于单线程。一个例外是 <b>DataSet</b>，它对多个阅读器是线程安全的。但是，在写的时候需要把 <b>DataSet</b> 锁定</span>。 </p><p>    <b>仅在需要的时候才用 COM Interop 访问 ADO</b> </p><p>    ADO.NET 的设计目的是成为许多应用程序的最佳解决方案。但是，有些应用程序需要只有使用 ADO 对象才有的功能，例如，ADO 多维 (ADOMD)。在这些情况下，应用程序可以用 COM Interop 访问 ADO。注意使用 COM Interop 访问具有 ADO 的数据会导致性能降低。在设计应用程序时，首先在实现用 COM Interop 访问 ADO 的设计之前，先确定 ADO.NET 是否满足设计需求。 </p><p>    摘自<a href="http://ltp.cnblogs.com/">【李天平】</a></p><img src ="http://www.cnitblog.com/sugar/aggbug/6766.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sugar/" target="_blank">sugar</a> 2006-02-21 10:01 <a href="http://www.cnitblog.com/sugar/archive/2006/02/21/6766.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>61条面向对象设计的经验原则</title><link>http://www.cnitblog.com/sugar/archive/2006/02/16/6642.html</link><dc:creator>sugar</dc:creator><author>sugar</author><pubDate>Thu, 16 Feb 2006 00:52:00 GMT</pubDate><guid>http://www.cnitblog.com/sugar/archive/2006/02/16/6642.html</guid><wfw:comment>http://www.cnitblog.com/sugar/comments/6642.html</wfw:comment><comments>http://www.cnitblog.com/sugar/archive/2006/02/16/6642.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/sugar/comments/commentRss/6642.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sugar/services/trackbacks/6642.html</trackback:ping><description><![CDATA[&#160;你不必严格遵守这些原则，违背它们也不会被处以宗教刑罚。但你应当把这些原则看成警铃，若违背了其中的一条，那么警铃就会响起 ----- Arthur J.Riel <br>(1)所有数据都应该隐藏在所在的类的内部。 <br/><br/>(2)类的使用者必须依赖类的共有接口，但类不能依赖它的使用者。 <br/><br/>(3)尽量减少类的协议中的消息。 <br/><br/>(4)实现所有类都理解的最基本公有接口[例如，拷贝操作(深拷贝和浅拷贝)、相等性判断、正确输出内容、从ASCII描述解析等等]。 <br/><br/>(5)不要把实现细节(例如放置共用代码的私有函数)放到类的公有接口中。 <br/><br/>如果类的两个方法有一段公共代码，那么就可以创建一个防止这些公共代码的私有函数。 <br/><br/>(6)不要以用户无法使用或不感兴趣的东西扰乱类的公有接口。 <br/><br/>(7)类之间应该零耦合，或者只有导出耦合关系。也即，一个类要么同另一个类毫无关系，要么只使用另一个类的公有接口中的操作。 <br/><br/>(8)类应该只表示一个关键抽象。 <br/><br/>包中的所有类对于同一类性质的变化应该是共同封闭的。一个变化若对一个包影响，则将对包中的所有类产生影响，而对其他的包不造成任何影响 . <br/><br/>(9)把相关的数据和行为集中放置。 <br/><br/>设计者应当留意那些通过get之类操作从别的对象中获取数据的对象。这种类型的行为暗示着这条经验原则被违反了。 <br/><br/>(10)把不相关的信息放在另一个类中(也即：互不沟通的行为)。 <br/><br/>朝着稳定的方向进行依赖. <br/><br/>(11)确保你为之建模的抽象概念是类，而不只是对象扮演的角色。 <br/><br/>(12)在水平方向上尽可能统一地分布系统功能，也即：按照设计，顶层类应当统一地共享工作。 <br/><br/>(13)在你的系统中不要创建全能类/对象。对名字包含Driver、Manager、System、Susystem的类要特别多加小心。 <br/><br/>规划一个接口而不是实现一个接口。 <br/><br/>(14)对公共接口中定义了大量访问方法的类多加小心。大量访问方法意味着相关数据和行为没有集中存放。 <br/><br/>(15)对包含太多互不沟通的行为的类多加小心。 <br/><br/>这个问题的另一表现是在你的应用程序中的类的公有接口中创建了很多的get和set函数。 <br/><br/>(16)在由同用户界面交互的面向对象模型构成的应用程序中，模型不应该依赖于界面，界面则应当依赖于模型。 <br/><br/>(17)尽可能地按照现实世界建模(我们常常为了遵守系统功能分布原则、避免全能类原则以及集中放置相关数据和行为的原则而违背这条原则) 。 <br/><br/>(18)从你的设计中去除不需要的类。 <br/><br/>一般来说，我们会把这个类降级成一个属性。 <br/><br/>(19)去除系统外的类。 <br/><br/>系统外的类的特点是，抽象地看它们只往系统领域发送消息但并不接受系统领域内其他类发出的消息。 <br/><br/>(20)不要把操作变成类。质疑任何名字是动词或者派生自动词的类，特别是只有一个有意义行为的类。考虑一下那个有意义的行为是否应当迁移到已经存在或者尚未发现的某个类中。 <br/><br/>(21)我们在创建应用程序的分析模型时常常引入代理类。在设计阶段，我们常会发现很多代理没有用的，应当去除。 <br/><br/>(22)尽量减少类的协作者的数量。 <br/><br/>一个类用到的其他类的数目应当尽量少。 <br/><br/>(23)尽量减少类和协作者之间传递的消息的数量。 <br/><br/>(24)尽量减少类和协作者之间的协作量，也即：减少类和协作者之间传递的不同消息的数量。 <br/><br/>(25)尽量减少类的扇出，也即：减少类定义的消息数和发送的消息数的乘积。 <br/><br/>(26)如果类包含另一个类的对象，那么包含类应当给被包含的对象发送消息。也即：包含关系总是意味着使用关系。 <br/><br/>(27)类中定义的大多数方法都应当在大多数时间里使用大多数数据成员。 <br/><br/>(28)类包含的对象数目不应当超过开发者短期记忆的容量。这个数目常常是6。 <br/><br/>当类包含多于6个数据成员时，可以把逻辑相关的数据成员划分为一组，然后用一个新的包含类去包含这一组成员。 <br/><br/>(29)让系统功能在窄而深的继承体系中垂直分布。 <br/><br/>(30)在实现语义约束时，最好根据类定义来实现。这常常会导致类泛滥成灾，在这种情况下，约束应当在类的行为中实现，通常是在构造函数中实现，但不是必须如此。 <br/><br/>(31)在类的构造函数中实现语义约束时，把约束测试放在构造函数领域所允许的尽量深的包含层次中。 <br/><br/>(32)约束所依赖的语义信息如果经常改变，那么最好放在一个集中式的第3方对象中。 <br/><br/>(33)约束所依赖的语义信息如果很少改变，那么最好分布在约束所涉及的各个类中。 <br/><br/>(34)类必须知道它包含什么，但是不能知道谁包含它。 <br/><br/>(35)共享字面范围(也就是被同一个类所包含)的对象相互之间不应当有使用关系。 <br/><br/>(36)继承只应被用来为特化层次结构建模。 <br/><br/>(37)派生类必须知道基类，基类不应该知道关于它们的派生类的任何信息。 <br/><br/>(38)基类中的所有数据都应当是私有的，不要使用保护数据。 <br/><br/>类的设计者永远都不应该把类的使用者不需要的东西放在公有接口中。 <br/><br/>(39)在理论上，继承层次体系应当深一点，越深越好。 <br/><br/>(40)在实践中，继承层次体系的深度不应当超出一个普通人的短期记忆能力。一个广为接受的深度值是6。 <br/><br/>(41)所有的抽象类都应当是基类。 <br/><br/>(42)所有的基类都应当是抽象类。 <br/><br/>(43)把数据、行为和/或接口的共性尽可能地放到继承层次体系的高端。 <br/><br/>(44)如果两个或更多个类共享公共数据(但没有公共行为)，那么应当把公共数据放在一个类中，每个共享这个数据的类都包含这个类。 <br/><br/>(45)如果两个或更多个类有共同的数据和行为(就是方法)，那么这些类的每一个都应当从一个表示了这些数据和方法的公共基类继承。 <br/><br/>(46)如果两个或更多个类共享公共接口(指的是消息，而不是方法)，那么只有他们需要被多态地使用时，他们才应当从一个公共基类继承。 <br/><br/>(47)对对象类型的显示的分情况分析一般是错误的。在大多数这样的情况下，设计者应当使用多态。 <br/><br/>(48)对属性值的显示的分情况分析常常是错误的。类应当解耦合成一个继承层次结构，每个属性值都被变换成一个派生类。 <br/><br/>(49)不要通过继承关系来为类的动态语义建模。试图用静态语义关系来为动态语义建模会导致在运行时切换类型。 <br/><br/>(50)不要把类的对象变成派生类。对任何只有一个实例的派生类都要多加小心。 <br/><br/>(51)如果你觉得需要在运行时刻创建新的类，那么退后一步以认清你要创建的是对象。现在，把这些对象概括成一个类。 <br/><br/>(52)在派生类中用空方法(也就是什么也不做的方法)来覆写基类中的方法应当是非法的。 <br/><br/>(53)不要把可选包含同对继承的需要相混淆。把可选包含建模成继承会带来泛滥成灾的类。 <br/><br/>(54)在创建继承层次时，试着创建可复用的框架，而不是可复用的组件。 <br/><br/>(55)如果你在设计中使用了多重继承，先假设你犯了错误。如果没犯错误，你需要设法证明。 <br/><br/>(56)只要在面向对象设计中用到了继承，问自己两个问题：(1)派生类是否是它继承的那个东西的一个特殊类型？(2)基类是不是派生类的一部分？ <br/><br/>(57)如果你在一个面向对象设计中发现了多重继承关系，确保没有哪个基类实际上是另一个基类的派生类。 <br/><br/>(58)在面向对象设计中如果你需要在包含关系和关联关系间作出选择，请选择包含关系。 <br/><br/>(59)不要把全局数据或全局函数用于类的对象的薄记工作。应当使用类变量或类方法。 <br/><br/>(60)面向对象设计者不应当让物理设计准则来破坏他们的逻辑设计。但是，在对逻辑设计作出决策的过程中我们经常用到物理设计准则。 <br/><br/>(61)不要绕开公共接口去修改对象的状态。 <br/><br/>摘自：《OOD 启思录》 Arthur J.Riel <br/><img src ="http://www.cnitblog.com/sugar/aggbug/6642.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sugar/" target="_blank">sugar</a> 2006-02-16 08:52 <a href="http://www.cnitblog.com/sugar/archive/2006/02/16/6642.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>申请 WB Editor 2 注册码</title><link>http://www.cnitblog.com/sugar/archive/2005/12/29/5870.html</link><dc:creator>sugar</dc:creator><author>sugar</author><pubDate>Thu, 29 Dec 2005 01:30:00 GMT</pubDate><guid>http://www.cnitblog.com/sugar/archive/2005/12/29/5870.html</guid><wfw:comment>http://www.cnitblog.com/sugar/comments/5870.html</wfw:comment><comments>http://www.cnitblog.com/sugar/archive/2005/12/29/5870.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cnitblog.com/sugar/comments/commentRss/5870.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/sugar/services/trackbacks/5870.html</trackback:ping><description><![CDATA[<DIV class=post twffan="done">
<DIV class=posthead twffan="done">
<H2><A class=singleposttitle id=viewpost1_TitleUrl href="http://yysun.cnblogs.com/archive/2005/12/04/290661.html"></A>&nbsp;</H2>摘自 <A href="http://yysun.cnblogs.com/">yysun</A> <BR><BR><STRONG>申请</STRONG></DIV>
<DIV class=postbody twffan="done">
<P>* 您在您的博客网页上放置好 WB Editor 2 的小贴图和连接。<BR>* 发 email 至 support @ wbeditor.com 申请<BR>* email 标题中必须注明：申请WB Editor 2 注册码<BR>* email 正文必须复制以下文字，并填入您的信息<BR>申请 WB Editor 2 注册码的博客网页 URL：[http:// ...]<BR>申请人的姓名：[姓名]<BR>申请人的 email：[email]<BR>放置 WB Editor 2 的小贴图和连接起始日期：[日期]</P>
<P><STRONG>接受使用协议</STRONG></P>
<P>wbeditor.com 在收到您的申请信后，将审核您的博客网页，然后通过 email 发送给您使用下协议：<BR><BR>1、申请人同意 wbeditor.com 赠送&nbsp;WB Editor 2 注册码的以下条件：<BR>2、申请 WB Editor 2 注册码的博客网页至少已经存在了&nbsp;3 个月。<BR>3、申请人同意在申请 WB Editor 2 注册码的博客网页上放置 WB Editor 2 的小贴图至少 100 天。<BR>4、小贴图上是 <A href="http://www.wbeditor.com/">www.wbeditor.com</A> 主页上的六个 wbeditor stickers 之一。<BR><A href="http://www.wbeditor.com/"><IMG height=24 src="http://www.wbeditor.com/images/wbeditor1.gif" width=94 border=0 twffan="done"></A>&nbsp;<A href="http://www.wbeditor.com/"><IMG height=24 src="http://www.wbeditor.com/images/wbeditor2.gif" width=94 border=0 twffan="done"></A>&nbsp;<A href="http://www.wbeditor.com/"><IMG height=24 src="http://www.wbeditor.com/images/wbeditor3.gif" width=94 border=0 twffan="done"></A> <BR><A href="http://www.wbeditor.com/"><IMG height=15 src="http://www.wbeditor.com/images/wbeditor_st1.gif" width=80 border=0 twffan="done"></A>&nbsp;<A href="http://www.wbeditor.com/"><IMG height=15 src="http://www.wbeditor.com/images/wbeditor_st2.gif" width=80 border=0 twffan="done"></A>&nbsp;<A href="http://www.wbeditor.com/"><IMG height=15 src="http://www.wbeditor.com/images/wbeditor_st3.gif" width=80 border=0 twffan="done"></A> <BR>5、小贴图上必须有连接至 <A href="http://www.wbeditor.com/">www.wbeditor.com</A>。<BR>6、申请人同意仅仅在申请 WB Editor 2 注册码的博客网页使用获赠的注册码。<BR>7、申请人同意遵守 WB Editor 2 的用户协议 (<A href="http://www.wbeditor.com/content/view/18/32">http://www.wbeditor.com/content/view/18/32</A>)。<BR>8、wbeditor.com 唯一有权决定是否赠送 WB Editor 2 的注册码。<BR>9、wbeditor.com 唯一有WB Editor 2 的注册码赠送活动的解释权。</P>
<P><STRONG>发送注册码</STRONG></P>
<P>如果您通过 email 回复同意使用协议，wbeditor.com 将发送 WB Editor 2 的注册码给您。</P>
<P>WB Editor 2 的注册码赠送活动时间：2005年12月5日 至 1006年1月5日。</P></DIV></DIV><img src ="http://www.cnitblog.com/sugar/aggbug/5870.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/sugar/" target="_blank">sugar</a> 2005-12-29 09:30 <a href="http://www.cnitblog.com/sugar/archive/2005/12/29/5870.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>