﻿<?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-网站开发-随笔分类-Petshop4.0 案例分析</title><link>http://www.blogjava.net/ljy032/category/28377.html</link><description>asp.net</description><language>zh-cn</language><lastBuildDate>Wed, 26 Dec 2007 11:54:12 GMT</lastBuildDate><pubDate>Wed, 26 Dec 2007 11:54:12 GMT</pubDate><ttl>60</ttl><item><title>petshop4.0设计说明asp.net初学者</title><link>http://www.blogjava.net/ljy032/archive/2007/12/26/170637.html</link><dc:creator>风雨兼程</dc:creator><author>风雨兼程</author><pubDate>Wed, 26 Dec 2007 09:05:00 GMT</pubDate><guid>http://www.blogjava.net/ljy032/archive/2007/12/26/170637.html</guid><wfw:comment>http://www.blogjava.net/ljy032/comments/170637.html</wfw:comment><comments>http://www.blogjava.net/ljy032/archive/2007/12/26/170637.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljy032/comments/commentRss/170637.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljy032/services/trackbacks/170637.html</trackback:ping><description><![CDATA[petshop4.0设计说明 <br />
一、项目名称及描述：(实现步骤为：4-3-6-5-2-1)<br />
1、WEB＝表示层<br />
2、BLL＝业务逻辑层<br />
3、IDAL＝数据访问层接口定义<br />
4、Model＝业务实体<br />
5、DALFactory＝数据层的抽象工厂(创建反射)<br />
6、SQLServerDAL＝SQLServer数据访问层 / OracleDAL＝Oracle数据访问层
<p>DBUtility 数据库访问组件基础类</p>
<p>二、项目引用关系<br />
1、Web 引用 BLL。<br />
2、BLL 引用 IDAL，Model，使用DALFactory创建实例。<br />
3、IDAL 引用 Model。<br />
4、Model 无引用。<br />
5、DALFactory 引用IDAL，通过读取web.config里设置的程序集，加载类的实例，返回给BLL使用。<br />
6、SQLServerDAL 引用 Model和IDAL，被DALFactory加载的程序集，实现接口里的方法。 </p>
<p><br />
三、实现步骤<br />
1、创建Model，实现业务实体。<br />
2、创建IDAL，实现接口。<br />
3、创建SQLServerDAL，实现接口里的方法。<br />
4、增加web.config里的配置信息，为SQLServerDAL的程序集。<br />
5、创建DALFactory，返回程序集的指定类的实例。<br />
6、创建BLL，调用DALFactory，得到程序集指定类的实例，完成数据操作方法。<br />
7、创建WEB，调用BLL里的数据操作方法。</p>
<p>注意：<br />
1、web.config里的程序集名称必须与SQLServerDAL里的输出程序集名称一致。<br />
2、DALFactory里只需要一个DataAccess类，可以完成创建所有的程序集实例。<br />
3、项目创建后，注意修改各项目的默认命名空间和程序集名称。<br />
4、注意修改解决方案里的项目依赖。<br />
5、注意在解决方案里增加各项目引用。</p>
<img src ="http://www.blogjava.net/ljy032/aggbug/170637.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljy032/" target="_blank">风雨兼程</a> 2007-12-26 17:05 <a href="http://www.blogjava.net/ljy032/archive/2007/12/26/170637.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在PetShop 4.0中ASP.NET缓存的实现 </title><link>http://www.blogjava.net/ljy032/archive/2007/12/26/170547.html</link><dc:creator>风雨兼程</dc:creator><author>风雨兼程</author><pubDate>Wed, 26 Dec 2007 04:07:00 GMT</pubDate><guid>http://www.blogjava.net/ljy032/archive/2007/12/26/170547.html</guid><wfw:comment>http://www.blogjava.net/ljy032/comments/170547.html</wfw:comment><comments>http://www.blogjava.net/ljy032/archive/2007/12/26/170547.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljy032/comments/commentRss/170547.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljy032/services/trackbacks/170547.html</trackback:ping><description><![CDATA[<p>PetShop作为一个B2C的宠物网上商店，需要充分考虑访客的用户体验，如果因为数据量大而导致Web服务器的响应不及时，页面和查询数据迟迟得不到结果，会因此而破坏客户访问网站的心情，在耗尽耐心的等待后，可能会失去这一部分客户。无疑，这是非常糟糕的结果。因而在对其进行体系架构设计时，整个系统的性能就显得殊为重要。然而，我们不能因噎废食，因为专注于性能而忽略数据的正确性。在PetShop 3.0版本以及之前的版本，因为ASP.NET缓存的局限性，这一问题并没有得到很好的解决。PetShop 4.0则引入了SqlCacheDependency特性，使得系统对缓存的处理较之以前大为改观。</p>
<p>4.3.1&nbsp; CacheDependency接口</p>
<p>PetShop 4.0引入了SqlCacheDependency特性，对Category、Product和Item数据表对应的缓存实施了SQL Cache Invalidation技术。当对应的数据表数据发生更改后，该技术能够将相关项从缓存中移除。实现这一技术的核心是SqlCacheDependency类，它继承了CacheDependency类。然而为了保证整个架构的可扩展性，我们也允许设计者建立自定义的CacheDependency类，用以扩展缓存依赖。这就有必要为CacheDependency建立抽象接口，并在web.config文件中进行配置。</p>
<p>在PetShop 4.0的命名空间PetShop.ICacheDependency中，定义了名为IPetShopCacheDependency接口，它仅包含了一个接口方法：<br />
public interface IPetShopCacheDependency<br />
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; AggregateCacheDependency GetDependency();<br />
}</p>
<p>AggregateCacheDependency是.Net Framework 2.0新增的一个类，它负责监视依赖项对象的集合。当这个集合中的任意一个依赖项对象发生改变时，该依赖项对象对应的缓存对象都将被自动移除。<br />
AggregateCacheDependency类起到了组合CacheDependency对象的作用，它可以将多个CacheDependency对象甚至于不同类型的CacheDependency对象与缓存项建立关联。由于PetShop需要为Category、Product和Item数据表建立依赖项，因而IPetShopCacheDependency的接口方法GetDependency()其目的就是返回建立了这些依赖项的AggregateCacheDependency对象。</p>
<p>4.3.2&nbsp; CacheDependency实现</p>
<p>CacheDependency的实现正是为Category、Product和Item数据表建立了对应的SqlCacheDependency类型的依赖项，如代码所示：<br />
public abstract class TableDependency : IPetShopCacheDependency<br />
{<br />
&nbsp;&nbsp;&nbsp; // This is the separator that's used in web.config<br />
&nbsp;&nbsp;&nbsp; protected char[] configurationSeparator = new char[] { ',' };</p>
<p>&nbsp;&nbsp;&nbsp; protected AggregateCacheDependency dependency = new AggregateCacheDependency();<br />
&nbsp;&nbsp;&nbsp; protected TableDependency(string configKey)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string dbName = ConfigurationManager.AppSettings["CacheDatabaseName"];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string tableConfig = ConfigurationManager.AppSettings[configKey];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string[] tables = tableConfig.Split(configurationSeparator);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach (string tableName in tables)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dependency.Add(new SqlCacheDependency(dbName, tableName));<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public AggregateCacheDependency GetDependency()<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return dependency;<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>需要建立依赖项的数据库与数据表都配置在web.config文件中，其设置如下：<br />
&lt;add key="CacheDatabaseName" value="MSPetShop4"/&gt;<br />
&lt;add key="CategoryTableDependency" value="Category"/&gt;<br />
&lt;add key="ProductTableDependency" value="Product,Category"/&gt;<br />
&lt;add key="ItemTableDependency" value="Product,Category,Item"/&gt;</p>
<p>根据各个数据表间的依赖关系，因而不同的数据表需要建立的依赖项也是不相同的，从配置文件中的value值可以看出。然而不管建立依赖项的多寡，其创建的行为逻辑都是相似的，因而在设计时，抽象了一个共同的类TableDependency，并通过建立带参数的构造函数，完成对依赖项的建立。由于接口方法GetDependency()的实现中，返回的对象dependency是在受保护的构造函数创建的，因此这里的实现方式也可以看作是Template Method模式的灵活运用。例如TableDependency的子类Product，就是利用父类的构造函数建立了Product、Category数据表的SqlCacheDependency依赖：<br />
public class Product : TableDependency<br />
{<br />
&nbsp;&nbsp;&nbsp; public Product() : base("ProductTableDependency") { }<br />
}</p>
<p>如果需要自定义CacheDependency，那么创建依赖项的方式又有不同。然而不管是创建SqlCacheDependency对象，还是自定义的CacheDependency对象，都是将这些依赖项添加到AggregateCacheDependency类中，因而我们也可以为自定义CacheDependency建立专门的类，只要实现IPetShopCacheDependency接口即可。</p>
<p>4.3.3&nbsp; CacheDependency工厂</p>
<p>继承了抽象类TableDependency的Product、Category和Item类均需要在调用时创建各自的对象。由于它们的父类TableDependency实现了接口IPetShopCacheDependency，因而它们也间接实现了IPetShopCacheDependency接口，这为实现工厂模式提供了前提。</p>
<p>在PetShop 4.0中，依然利用了配置文件和反射技术来实现工厂模式。命名空间PetShop.CacheDependencyFactory中，类DependencyAccess即为创建IPetShopCacheDependency对象的工厂类：<br />
public static class DependencyAccess<br />
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public static IPetShopCacheDependency CreateCategoryDependency()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return LoadInstance("Category");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public static IPetShopCacheDependency CreateProductDependency()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return LoadInstance("Product");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public static IPetShopCacheDependency CreateItemDependency()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return LoadInstance("Item");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; private static IPetShopCacheDependency LoadInstance(string className)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string fullyQualifiedClass = path + "." + className;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
整个工厂模式的实现如图4-3所示：</p>
<p align="center"><img height="279" alt="4-3.gif" src="http://www.1-100.org/AspNet/UploadFiles_6345/200611/20061102063110194.gif" width="547" border="0" mce_src="http://www.1-100.org/AspNet/UploadFiles_6345/200611/20061102063110194.gif" /><br />
&nbsp;图4-3 CacheDependency工厂</p>
<p>虽然DependencyAccess类创建了实现了IPetShopCacheDependency接口的类Category、Product、Item，然而我们之所以引入IPetShopCacheDependency接口，其目的就在于获得创建了依赖项的AggregateCacheDependency类型的对象。我们可以调用对象的接口方法GetDependency()，如下所示：<br />
AggregateCacheDependency dependency = DependencyAccess.CreateCategoryDependency().GetDependency();</p>
<p>为了方便调用者，似乎我们可以对DependencyAccess类进行改进，将原有的CreateCategoryDependency()方法，修改为创建AggregateCacheDependency类型对象的方法。</p>
<p>然而这样的做法扰乱了作为工厂类的DependencyAccess的本身职责，且创建IPetShopCacheDependency接口对象的行为仍然有可能被调用者调用，所以保留原有的DependencyAccess类仍然是有必要的。</p>
<p>在PetShop 4.0的设计中，是通过引入Facade模式以方便调用者更加简单地获得AggregateCacheDependency类型对象。</p>
<p>4.3.4&nbsp; 引入Facade模式</p>
<p>利用Facade模式可以将一些复杂的逻辑进行包装，以方便调用者对这些复杂逻辑的调用。就好像提供一个统一的门面一般，将内部的子系统封装起来，统一为一个高层次的接口。一个典型的Facade模式示意图如下所示：</p>
<p align="center"><img height="273" alt="4-4.gif" src="http://www.1-100.org/AspNet/UploadFiles_6345/200611/20061102063110888.gif" width="255" border="0" mce_src="http://www.1-100.org/AspNet/UploadFiles_6345/200611/20061102063110888.gif" /><br />
图4-4 Facade模式</p>
<p>Facade模式的目的并非要引入一个新的功能，而是在现有功能的基础上提供一个更高层次的抽象，使得调用者可以直接调用，而不用关心内部的实现方式。以CacheDependency工厂为例，我们需要为调用者提供获得AggregateCacheDependency对象的简便方法，因而创建了DependencyFacade类：<br />
public static class DependencyFacade<br />
{<br />
&nbsp;&nbsp;&nbsp; private static readonly string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];<br />
&nbsp;&nbsp;&nbsp; public static AggregateCacheDependency GetCategoryDependency()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!string.IsNullOrEmpty(path))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return DependencyAccess.CreateCategoryDependency().GetDependency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public static AggregateCacheDependency GetProductDependency()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!string.IsNullOrEmpty(path))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return DependencyAccess.CreateProductDependency().GetDependency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; public static AggregateCacheDependency GetItemDependency()<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!string.IsNullOrEmpty(path))<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return DependencyAccess.CreateItemDependency().GetDependency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>DependencyFacade类封装了获取AggregateCacheDependency类型对象的逻辑，如此一来，调用者可以调用相关方法获得创建相关依赖项的AggregateCacheDependency类型对象：<br />
AggregateCacheDependency dependency = DependencyFacade.GetCategoryDependency();</p>
<p>比起直接调用DependencyAccess类的GetDependency()方法而言，除了方法更简单之外，同时它还对CacheDependencyAssembly配置节进行了判断，如果其值为空，则返回null对象。</p>
<p>在PetShop.Web的App_Code文件夹下，静态类WebUtility的GetCategoryName()和GetProductName()方法调用了DependencyFacade类。例如GetCategoryName()方法：<br />
public static string GetCategoryName(string categoryId)<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp; Category category = new Category();<br />
&nbsp;&nbsp;&nbsp;&nbsp; if (!enableCaching)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return category.GetCategory(categoryId).Name;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; string cacheKey = string.Format(CATEGORY_NAME_KEY, categoryId);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; // 检查缓存中是否存在该数据项;<br />
&nbsp;&nbsp;&nbsp;&nbsp; string data = (string)HttpRuntime.Cache[cacheKey];<br />
&nbsp;&nbsp;&nbsp;&nbsp; if (data == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 通过web.config的配置获取duration值;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int cacheDuration = int.Parse(ConfigurationManager.AppSettings["CategoryCacheDuration"]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 如果缓存中不存在该数据项，则通过业务逻辑层访问数据库获取;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data = category.GetCategory(categoryId).Name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 通过Facade类创建AggregateCacheDependency对象;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AggregateCacheDependency cd = DependencyFacade.GetCategoryDependency();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 将数据项以及AggregateCacheDependency 对象存储到缓存中;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpRuntime.Cache.Add(cacheKey, data, cd, DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration, CacheItemPriority.High, null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data;<br />
}</p>
<p>GetCategoryName()方法首先会检查缓存中是否已经存在CategoryName数据项，如果已经存在，就通过缓存直接获取数据；否则将通过业务逻辑层调用数据访问层访问数据库获得CategoryName，在获得了CategoryName后，会将新获取的数据连同DependencyFacade类创建的AggregateCacheDependency对象添加到缓存中。</p>
<p>WebUtility静态类被表示层的许多页面所调用，例如Product页面：<br />
public partial class Products : System.Web.UI.Page<br />
{<br />
&nbsp;&nbsp;&nbsp; protected void Page_Load(object sender, EventArgs e)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Page.Title = WebUtility.GetCategoryName(Request.QueryString["categoryId"]);<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>显示页面title的逻辑是放在Page_Load事件方法中，因而每次打开该页面都要执行获取CategoryName的方法。如果没有采用缓存机制，当Category数据较多时，页面的显示就会非常缓慢。</p>
<p>4.3.5&nbsp; 引入Proxy模式</p>
<p>业务逻辑层BLL中与Product、Category、Item有关的业务方法，其实现逻辑是调用数据访问层（DAL）对象访问数据库，以获取相关数据。为了改善系统性能，我们就需要为这些实现方法增加缓存机制的逻辑。当我们操作增加了缓存机制的业务对象时，对于调用者而言，应与BLL业务对象的调用保持一致。也即是说，我们需要引入一个新的对象去控制原来的BLL业务对象，这个新的对象就是Proxy模式中的代理对象。</p>
<p>以PetShop.BLL.Product业务对象为例，PetShop为其建立了代理对象ProductDataProxy，并在GetProductByCategory()等方法中，引入了缓存机制，例如：<br />
public static class ProductDataProxy<br />
{</p>
<p>&nbsp;&nbsp;&nbsp; private static readonly int productTimeout = int.Parse(ConfigurationManager.AppSettings["ProductCacheDuration"]);<br />
&nbsp;&nbsp;&nbsp; private static readonly bool enableCaching = bool.Parse(ConfigurationManager.AppSettings["EnableCaching"]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp; public static IList<br />
GetProductsByCategory(string category)<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Product product = new Product();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!enableCaching)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return product.GetProductsByCategory(category);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string key = "product_by_category_" + category;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IList data = (IList )HttpRuntime.Cache[key];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Check if the data exists in the data cache<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (data == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data = product.GetProductsByCategory(category);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Create a AggregateCacheDependency object from the factory<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AggregateCacheDependency cd = DependencyFacade.GetProductDependency();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Store the output in the data cache, and Add the necessary AggregateCacheDependency object<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(productTimeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return data;<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>与业务逻辑层Product对象的GetProductsByCategory()方法相比，增加了缓存机制。当缓存内不存在相关数据项时，则直接调用业务逻辑层Product的GetProductsByCategory()方法来获取数据，并将其与对应的AggregateCacheDependency对象一起存储在缓存中。</p>
<p>引入Proxy模式，实现了在缓存级别上对业务对象的封装，增强了对业务对象的控制。由于暴露在对象外的方法是一致的，因而对于调用方而言，调用代理对象与真实对象并没有实质的区别。</p>
<p>从职责分离与分层设计的角度分析，我更希望这些Proxy对象是被定义在业务逻辑层中，而不像在PetShop的设计那样，被划分到表示层UI中。此外，如果需要考虑程序的可扩展性与可替换性，我们还可以为真实对象与代理对象建立统一的接口或抽象类。然而，单以PetShop的表示层调用来看，采用静态类与静态方法的方式，或许更为合理。我们需要谨记，&#8220;过度设计&#8221;是软件设计的警戒线。</p>
<p>如果需要对UI层采用缓存机制，将应用程序数据存放到缓存中，就可以调用这些代理对象。以ProductsControl用户控件为例，调用方式如下：<br />
productsList.DataSource = ProductDataProxy.GetProductsByCategory(categoryKey);</p>
<p>productsList对象属于自定义的CustomList类型，这是一个派生自System.Web.UI.WebControls.DataList控件的类，它的DataSource属性可以接受IList集合对象。<br />
不过在PetShop 4.0的设计中，对于类似于ProductsControl类型的控件而言，采用的缓存机制是页输出缓存。我们可以从ProductsControl.ascx页面的Source代码中发现端倪：<br />
&lt;%@ OutputCache Duration="100000" VaryByParam="page;categoryId" %&gt;</p>
<p>与ASP.NET 1.x的页输出缓存不同的是，在ASP.NET 2.0中，为ASP.NET用户控件新引入了CachePolicy属性，该属性的类型为ControlCachePolicy类，它以编程方式实现了对ASP.NET用户控件的输出缓存设置。我们可以通过设置ControlCachePolicy类的Dependency属性，来设置与该用户控件相关的依赖项，例如在ProductsControl用户控件中，进行如下的设置：<br />
protected void Page_Load(object sender, EventArgs e)<br />
{<br />
&nbsp;&nbsp;&nbsp; this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();<br />
}</p>
<p>采用页输出缓存，并且利用ControlCachePolicy设置输出缓存，能够将业务数据与整个页面放入到缓存中。这种方式比起应用程序缓存而言，在性能上有很大的提高。同时，它又通过引入的SqlCacheDependency特性有效地避免了&#8220;数据过期&#8221;的缺点，因而在PetShop 4.0中被广泛采用。相反，之前为Product、Category、Item业务对象建立的代理对象则被&#8220;投闲散置&#8221;，仅仅作为一种设计方法的展示而&#8220;幸存&#8221;与整个系统的源代码中。</p>
<img src ="http://www.blogjava.net/ljy032/aggbug/170547.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljy032/" target="_blank">风雨兼程</a> 2007-12-26 12:07 <a href="http://www.blogjava.net/ljy032/archive/2007/12/26/170547.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>IList&lt;CategoryInfo&gt; GetCategories();的问题</title><link>http://www.blogjava.net/ljy032/archive/2007/12/26/170538.html</link><dc:creator>风雨兼程</dc:creator><author>风雨兼程</author><pubDate>Wed, 26 Dec 2007 03:44:00 GMT</pubDate><guid>http://www.blogjava.net/ljy032/archive/2007/12/26/170538.html</guid><wfw:comment>http://www.blogjava.net/ljy032/comments/170538.html</wfw:comment><comments>http://www.blogjava.net/ljy032/archive/2007/12/26/170538.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljy032/comments/commentRss/170538.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljy032/services/trackbacks/170538.html</trackback:ping><description><![CDATA[petshop4.0中的一段代码 &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; public &nbsp; interface &nbsp; ICategory &nbsp; { &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; /// &nbsp; &lt;summary&gt; &nbsp; <br />
&nbsp; /// &nbsp; Method &nbsp; to &nbsp; get &nbsp; all &nbsp; categories &nbsp; <br />
&nbsp; /// &nbsp; &lt;/summary&gt; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /// &nbsp; &lt;returns&gt;Interface &nbsp; to &nbsp; Model &nbsp; Collection &nbsp; Generic &nbsp; of &nbsp; categories&lt;/returns&gt; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; IList&lt;CategoryInfo&gt; &nbsp; GetCategories(); &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /// &nbsp; &lt;summary&gt; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /// &nbsp; Get &nbsp; information &nbsp; on &nbsp; a &nbsp; specific &nbsp; category &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /// &nbsp; &lt;/summary&gt; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /// &nbsp; &lt;param &nbsp; name="categoryId"&gt;Unique &nbsp; identifier &nbsp; for &nbsp; a &nbsp; category&lt;/param&gt; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /// &nbsp; &lt;returns&gt;Business &nbsp; Entity &nbsp; representing &nbsp; an &nbsp; category&lt;/returns&gt; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CategoryInfo &nbsp; GetCategory(string &nbsp; categoryId); &nbsp; <br />
&nbsp; } &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; 我知道IList&lt;CategoryInfo&gt;是范型 &nbsp; <br />
&nbsp; 表示list中的item是CategoryInfo对象 &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; 请问为什么用IList&lt;CategoryInfo&gt; &nbsp; <br />
&nbsp; 用List&lt;CategoryInfo&gt;可以吗？ &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; 两者有什么区别？谢谢&nbsp;&nbsp; <br />
<br />
没有什么区别，这样写灵活性大，实现ilist接口的类很多，你写成list后，也许以后你要改成非list的，就会要改很多代码<br />
举个例子 &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; RenderControlToString(DataList &nbsp; L//Control &nbsp; C) &nbsp; <br />
&nbsp; &nbsp; <br />
&nbsp; 你认为是写control还是写datalist代码的通用性高?<br />
<br />
&nbsp; OOP编码原则:尽可能用接口编程<br />
 <img src ="http://www.blogjava.net/ljy032/aggbug/170538.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljy032/" target="_blank">风雨兼程</a> 2007-12-26 11:44 <a href="http://www.blogjava.net/ljy032/archive/2007/12/26/170538.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于sqlhelper.cs </title><link>http://www.blogjava.net/ljy032/archive/2007/12/26/170508.html</link><dc:creator>风雨兼程</dc:creator><author>风雨兼程</author><pubDate>Wed, 26 Dec 2007 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/ljy032/archive/2007/12/26/170508.html</guid><wfw:comment>http://www.blogjava.net/ljy032/comments/170508.html</wfw:comment><comments>http://www.blogjava.net/ljy032/archive/2007/12/26/170508.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/ljy032/comments/commentRss/170508.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/ljy032/services/trackbacks/170508.html</trackback:ping><description><![CDATA[<p>public abstract class SqlHelper<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static readonly string connectionString = ConfigurationManager.ConnectionStrings["SqlConnString"].ConnectionString;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlConnection conn; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region open SqlConnection<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Open() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn = new SqlConnection(connectionString);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (conn.State != ConnectionState.Open)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Open(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region close SqlConnection<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Close() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (conn != null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; conn.Close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; conn.Dispose();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region prepare SqlCommand<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private static void PrepareCommand(SqlCommand cmd, CommandType cmdType, string cmdText, SqlParameter[] cmdParms) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Open();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Connection = conn;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.CommandType = cmdType;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.CommandText = cmdText;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cmdParms != null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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; foreach (SqlParameter parm in cmdParms)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Parameters.Add(parm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region parm cache<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用一个哈希表来保存缓存的参数 只缓存参数名<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 哈希表的特点:一个键对应一个值key对value(为object需要类型转化)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不能出现两个相同的键 否则error<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面的哈希表parmCache定义为static即一次定义全局使用<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所以可能会出现有人在读的时候，有人在写，一般会用Lock就像Asp中用Application["count"]来统计点击数一样<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 要先锁后解锁<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 但.net框架提供了Synchroized&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sync和syncroize中文意思 同步，同时发生<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 来提供这一操作<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; private static Hashtable parmCache = Hashtable.Synchronized(new Hashtable());</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void CacheParameters(string cacheKey, params SqlParameter[] commandParameters) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parmCache[cacheKey] = commandParameters;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、为何要克隆呢 为何不直接return cachedParms<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有一个参数数组<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlParameter[] parms={<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new SqlParameter("@num1",SqlDbType.Int,4),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new SqlParameter("@num2",SqlDbType.Int,4)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 缓存该数组<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用户a和b都执行插入操作<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a用户插入了1,1 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b用户插入了2,2 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果不用克隆的话，参数数组只有一份<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 而2个用户需要根据不同的情况赋于不同的值<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 所以就用了克隆了<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、(ICloneable)cachedParms[i]先将HashTable转为ICloneable这样HashTable就具有了Clone()克隆方法了<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 克隆一份后是什么类型呢，，当然要强制转化为(SqlParameter)了<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后将它赋值给clonedParms[i]<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static SqlParameter[] GetCachedParameters(string cacheKey) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (cachedParms == null)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return null;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; cachedParms.Length; i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return clonedParms;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //below method support sqltext and procedure</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region ExecuteReader<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; parms的作用，这也是一个知识点<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 举例:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ExecuteReader(*,*,null)成功运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ExecuteReader(*,*,new SqlParameter(*))成功运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ExecuteReader(*,*,new SqlParameter(*),new SqlParameter(*))成功运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ExecuteReader(*,*,{new SqlParameter(*),new SqlParameter(*),})成功运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 它让参数类型和参数个数任意<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这可给了不是一般的好处，你不必为SqlParameter和SqlParameter[]进行重载，写上两个函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 又为null写上一个函数，因为null会不明确调用SqlParameter的函数还是SqlParameter[]的函数<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 啥你不知道我在说什么，打屁屁,那回去看看c++的函数重载<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static SqlDataReader ExecuteReader(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand cmd = new SqlCommand();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrepareCommand(cmd, null, cmdType, cmdText, commandParameters);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Parameters.Clear();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return rdr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region ExecuteNonQuery<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void ExecuteNonQuery(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand cmd = new SqlCommand();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrepareCommand(cmd, cmdType, cmdText, commandParameters);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.ExecuteNonQuery();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Parameters.Clear();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region ExecuteScalar<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static object ExecuteScalar(CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SqlCommand cmd = new SqlCommand();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PrepareCommand(cmd, cmdType, cmdText, commandParameters);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; object val = cmd.ExecuteScalar();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cmd.Parameters.Clear();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return val;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</p>
<p><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
}</p>
 <img src ="http://www.blogjava.net/ljy032/aggbug/170508.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/ljy032/" target="_blank">风雨兼程</a> 2007-12-26 10:30 <a href="http://www.blogjava.net/ljy032/archive/2007/12/26/170508.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>