五十九:使用SQL缓存依赖项SqlCacheDependency_第1页
五十九:使用SQL缓存依赖项SqlCacheDependency_第2页
五十九:使用SQL缓存依赖项SqlCacheDependency_第3页
五十九:使用SQL缓存依赖项SqlCacheDependency_第4页
五十九:使用SQL缓存依赖项SqlCacheDependency_第5页
已阅读5页,还剩20页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、在ASP.NET 2.0中操作数据之五十九:使用SQL缓存依赖项SqlCacheDependency作者:heker2007 字体:增加 减小 类型:转载 时间:2016-05-17 我要评论当缓存数据库数据时,最理想的状态是数据一直驻留在内存,直到数据库发生了改动。在ASP.NET 2.0,可以通过编程或声明代码的方式使用SQL cache dependencies,配合SQL Server 2005来实现此功能。导言:在56和57章探讨的缓存技术使用的是基于时间的缓存周期,当过了某段时间后便将缓存数据从内存清除。当设置缓存时间为x秒时,数据在x秒内都是“新”的。当然,就

2、像在60章谈到的那样,对静态数据来说,x可延伸到web应用程序的整个生命周期(lifetime)。当缓存数据时,基于时间周期的技术因为其易用性而常常被采用,不过又常常不那么完美。理想的状态是这样的:数据库数据还是应缓存在内存,直到源数据(underlying data)发生改变时才从内存清除。这样的话可以最大化的获取缓存带来的性能上的好处,同时使“过时数据”(stale data)持续的时间最短。然而,为此,我们需要建立一种机制来探测数据库数据什么时候发生了改变,并将对应的缓存条目清除掉。ASP.NET 2.0提供的SqlCacheDependency class类和必要的下部基础构造(inf

3、rastructure)可以判断数据库什么时候发生了更改,以便将对应的缓存条目从内存清除掉。有2种技术可以判断源数据在什么时候发生了改变:polling 和notification。讨论完这2者之间的差别后,我们将创建必要的下部基础构造来支持polling,然后探讨如何使用SqlCacheDependency class类理解Notification and Polling正如前面所述,有2种方法来判断一个数据库里的数据在什么时候修改过:notification 和 polling.当使用notification的时候,数据库提示(alerts)ASP.NET对应某个具体查询的数据已经发生了改

4、变;于是对应的缓存条目将被清除。使用polling的时候,数据库服务器将包含某个表(tables)最近发生更改时的相关信息。ASP.NET周期性的对数据库进行检查,看哪些表在数据被缓存以后发生过改动,若改动过,对应的缓存条目将被清除。notification是对查询(query)而不是表(table)进行跟踪检查,相对polling而言,需要采取的步骤要少些。不过遗憾的是,只有在Microsoft SQL Server 2005的完整版(也就是non-Express版本)才能使用该功能。而Microsoft SQL Server的所有版本,从7.0 到2005都可以使用polling功能,因为

5、本系列教程使用的是SQL Server 2005的Express版本,在此我们将集中探讨建立和使用polling。关于SQL Server 2005的notification功能,你可以参阅本文结束部分的Further Reading。要使用polling,我们将设置数据库包含一个名为AspNet_SqlCacheTablesForChangeNotification的表。该表有3列:tableName, notificationCreated, 和changeId.对于哪些在web应用程序的SQL cache dependency里要用到的表,该表都有一条记录与之对应。tableName就是

6、具体某个表的名称;notificationCreated指明了添加记录时的date 和 time;而列changeId的类型是int,初始值是0,每当对应的表发生一次改动,其值就自动增加一次。除了表AspNet_SqlCacheTablesForChangeNotification外,数据库还需要为出现在SQL cache dependency里的每个表包含一个触发器(triggers),任何时候,只要表插入、更新、删除一条记录或在表AspNet_SqlCacheTablesForChangeNotification里的对应的changeId值增大的情况下就会执行触发器。当使用SqlCache

7、Dependency对象(object)来缓存数据时,ASP.NET将关注某个表的当前(current)的changeId值,一旦发现当前其值与数据库里面的changeId值不同时,就将该SqlCacheDependency对象清除。因为,changeId不吻合就意味着在完成数据缓存后,表又发生过改动。第一步:考察命令行程序aspnet_regsql.exe如上所述,使用polling方法时,必须对数据库进行设置以包含这些基础构造:一个预先定义的表(AspNet_SqlCacheTablesForChangeNotification),一些存储过程,以及基于在SQL cache depende

8、ncies里要用到的表的触发器。诸如这些表、存储过程、触发器等都可以通过命令行程序aspnet_regsql.exe来创建,该命令位于$WINDOWS$/Microsoft.NET/Framework/version文件夹。要创建表AspNet_SqlCacheTablesForChangeNotification以及相关的存储过程,可以在命令行这样运行:复制代码代码如下:/* For SQL Server authentication. */aspnet_regsql.exe -S server -U user -P password -d database -ed复制代码代码如下:/* F

9、or Windows Authentication. */aspnet_regsql.exe -S server -E -d database -ed注意:要运行这些命令,必须以db_securityadmin 和 db_ddladmin的身份登录数据库,更多详情请参阅作者博客:比如:在Windows身份认证模式下,对某个数据库服务器ScottsServer里的数据库pubs添加基础构造时,在命令行键入:复制代码代码如下:aspnet_regsql.exe -S ScottsServer -E -d pubs -ed完成了数据库级(database-level)基础构造的添加后,我们需要添加触

10、发器,再次使用aspnet_regsql.exe命令,不过用-t来指定"表名"(table name),且将-ed替换为-et,如下:复制代码代码如下:/* For SQL Server authentication. */aspnet_regsql.exe -S <i>server</i>-U <i>user</i> -P <i>password</i> -d <i>database</i> -t <i>tableName</i> -et复制代码代码如下

11、:/* For Windows Authentication. */aspnet_regsql.exe -S <i>server</i>-E -d <i>database</i> -t <i>tableName</i> -et要对ScottsServer里的表authors和titles添加触发器,这样做:复制代码代码如下:aspnet_regsql.exe -S ScottsServer -E -d pubs -t authors -etaspnet_regsql.exe -S ScottsServer -E -d pu

12、bs -t titles -et就本文而言,我们要对表Products, Categories,和Suppliers添加触发器,具体的命令在第三步探讨。第二步:在文件夹App_Data里引用一个Microsoft SQL Server 2005 Express版的数据库我们刚刚说过,为了添加必要的基础构造,aspnet_regsql.exe命令需要用到数据库和服务器的名称。但是对于放在文件夹App_Data里的一个Microsoft SQL Server 2005 Express的数据库而言,它的数据库名和服务器名又是什么呢?犯不着探究其数据库名和服务器名到底是什么,我发现最简单的方法是用SQ

13、L服务管理器(SQL Server Management Studio)来将该数据库认作localhost/SQLExpress database数据库,并重新命名。如果你的机器里已经安装了SQL Server 2005完整版,自然也就安装了SQL服务管理器。如果你安装的是Express版本的话,你可以免费下载Microsoft SQL Server Management Studio Express Edition.(首先,关闭Visual Studio,然后打开SQL Server Management Studio,在Windows Authentication模式里选择连接到local

14、host/SQLExpress.图1:连接到localhost/SQLExpress Server连接到服务器后,管理器将显示服务器,并将数据库、安全等以折叠的形式显示出来。在数据库文件夹上右击,选添加(Attach)项,这样将弹出Attach Databases对话框(见图2),点Add按钮,选择我们的web应用程序的App_Data文件夹里的NORTHWND.MDF数据库。图2:选App_Data文件夹里的NORTHWND.MDF数据库这样将会把数据库添加到Databases文件夹,且数据库的名称可能是该数据库文件的绝对路径(full path).出于简便的原则,我们将其重命名为一个更友好

15、(human-friendly)的名字,我将其命名为“DataTutorials”.图3:将新添加的数据库重命名第三步:对Northwind数据库添加Polling基础构造现在我们添加了App_Data文件夹里的NORTHWND.MDF数据库,让我们添加polling 基础构造吧,假定你已经将数据库重命名为“DataTutorials”, 运行如下的命令:复制代码代码如下:aspnet_regsql.exe -S localhost/SQLExpress -E -d DataTutorials -edaspnet_regsql.exe -S localhost/SQLExpress -E -d

16、 DataTutorials -t Products -etaspnet_regsql.exe -S localhost/SQLExpress -E -d DataTutorials -t Categories -etaspnet_regsql.exe -S localhost/SQLExpress -E -d DataTutorials -t Suppliers -et完成上述4个命令后,在Management Studio里右击数据库,进入任务子菜单(Tasks submenu),选分派(Detach)。然后关闭Management Studio并重新打开Visual Studio.打开V

17、isual Studio后,在服务器资源管理器里展开数据库,你可以看到有新增的表(AspNet_SqlCacheTablesForChangeNotification),新的存储过程,以及对应于表Products, Categories, 和Suppliers的触发器.图4:数据库包含了必需的Polling基础构造第四步:设置Polling服务完成上述步骤后,最后我们需要设置polling服务。这要用到Web.config文件,在里面指定要用到的数据库,以及检测频率(polling frequency),单位为毫秒。下面的代码是每隔1秒对Northwind数据库检测一次。?1234567891

18、0111213141516171819202122<?xml version="1.0"?><configuration> <connectionStrings> <add name="NORTHWNDConnectionString" connectionString=  "Data Source=./SQLEXPRESS;AttachDbFilename=|DataDirectory|/NORTHWND.MDF;  Integrated S

19、ecurity=True;User Instance=True"  providerName="System.Data.SqlClient"/> </connectionStrings> <system.web> .  <!- Configure the polling service used for SQL cache dependencies -> <caching>  <sqlCacheDepend

20、ency enabled="true" pollTime="1000" >  <databases>  <add name="NorthwindDB"   connectionStringName="NORTHWNDConnectionString" />  </databases>  </sqlCacheDependency> </ca

21、ching> </system.web></configuration>在<add>元素里的name值(“NorthwindDB”)是一个易读(human-readable)的名称,它与某个具体的数据库对应。当使用SQL cache dependencies的时候,我们需要引用在这里定义的数据库名。我们将在第六步考察怎样使用SqlCacheDependency class类来缓存数据。一旦确定了一个SQL cache dependency后,检测系统(polling system)每隔定义的pollTime那么多毫秒对<database

22、s>元素里的数据库进行连接,并执行名为AspNet_SqlCachePollingStoredProcedure的存储过该存储过程是我们在第三步使用aspnet_regsql.exe命令行工具添加的,它返回的是表AspNet_SqlCacheTablesForChangeNotification里的每条记录的tableName 和 changeId值。那些“过时”的SQL cache dependencies将会从内存清除掉。应在权衡性能和数据刷新(data staleness)的基础上设置pollTime.较小的pollTime值虽然导致请求数据库的次数增加,但能更快的将“过时&quo

23、t;的数据清除掉;较大的pollTime值虽然减少了对数据库的请求次数,但增加了“过时”的缓存条目的呆滞时间。还好,对数据库的请求只是执行一个简单的存储过程而已,该存储过程仅仅从一个简单的表返回很少的几行。你最好多测试几个不同的pollTime值,在平衡数据库访问和数据刷新2方面的情况下找出一个理想的值。pollTime值最小允许为500.注意:在上面的代码里,我们在<sqlCacheDependency>元素里指定了一个单一的pollTime值。其实你也可以在<add>元素里随意的指定一个pollTime值。当你指定了很多个数据库,且你想为每个数据库都指定一个检测频率

24、(polling frequency)时,这样做很有用。第五:声明SQL Cache Dependencies在第一到第四步骤,我们探讨了如何建立必需的数据库基础构造,以及设置检测系统(polling system).完成上述步骤后,现在我们可以通过编程或声明的方式,在添加缓存条目时使用SQL cache dependency.在本节,我们探讨如何使用声明的方式使用SQL cache dependencies,在第六步再探讨通过编程的方式。在使用ObjectDataSource缓存数据教程里,我们考察了声明ObjectDataSource控件的缓存功能。仅仅将EnableCaching属性设置

25、为true,并将acheDuration属性设置为某个时间间(timeinterval),ObjectDataSource控件就会自动地将从“源对象”(underlying object)返回的数据进行缓存。ObjectDataSource控件可以使用单个或多个SQL cache dependencies.为此,打开文件夹Caching里的SqlCacheDependencies.aspx页面,在设计模式里,从工具箱拖一个GridView控件到页面上,设置其ID为ProductsDeclarative ,从其智能标签里将其绑定到一个名为ProductsDataSourceDeclarative

26、的ObjectDataSource.图5:创建一个名为ProductsDataSourceDeclarative的ObjectDataSource设置该ObjectDataSource使用ProductsBLL类。在SELECT标签里选GetProducts()方法;在UPDATE标签里,选择包含3个输入参数productName,unitPrice,和productID的UpdateProduct重载方法;在INSERT 和 DELETE标签里选“(None)”.图6:使用包含3个输入参数的UpdateProduct重载方法图7:在INSERT和DELETE标签的下拉列表里选“(None)”

27、完成设置后,Visual Studio会为GridView里的每一列创建绑定列(BoundFields) 和CheckBoxFieldsL列。将ProductName, CategoryName, 和UnitPrice以外的列都删除,对其应用什么格式化都可以。在GridView的智能标签里启用分页、排序、编辑功能。Visual Studio会将ObjectDataSource控件的OldValuesParameterFormatString属性设置为original_0,为使GridView的编辑功能运行正常,要么删除该属性,要么将其设置为默认值:0.最后,在GridView上面添加一个Lab

28、el Web控件,设置其ID为ODSEvents,再将其EnableViewState属性设置为false.做完上述修改后,页面的声明代码看起来应该和下面的差不多。注意,我已经对GridView列的外观做了些定制,虽然这对SQL cache dependency功能来说并不是必要的。?1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556<asp:Label ID="ODSEvents" runat="ser

29、ver" EnableViewState="False" /> <asp:GridView ID="ProductsDeclarative" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ProductsDataSourceDeclarative" AllowPaging="True&qu

30、ot; AllowSorting="True"> <Columns> <asp:CommandField ShowEditButton="True" /> <asp:TemplateField HeaderText="Product" SortExpression="ProductName">  <EditItemTemplate>  <asp:TextBox ID="Prod

31、uctName" runat="server"   Text='<%# Bind("ProductName") %>' />  <asp:RequiredFieldValidator ID="RequiredFieldValidator1"   ControlToValidate="ProductName" Display="Dynamic"  &

32、#160;ErrorMessage="You must provide a name for the product."   SetFocusOnError="True"   runat="server">*</asp:RequiredFieldValidator>  </EditItemTemplate>  <ItemTemplate>  <asp:Label ID=

33、"Label2" runat="server"   Text='<%# Bind("ProductName") %>' />  </ItemTemplate> </asp:TemplateField> <asp:BoundField DataField="CategoryName" HeaderText="Category"  ReadOnly

34、="True" SortExpression="CategoryName" /> <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">  <EditItemTemplate>  $<asp:TextBox ID="UnitPrice" runat="server" Columns="8"

35、0;  Text='<%# Bind("UnitPrice", "0:N2") %>'></asp:TextBox>  <asp:CompareValidator ID="CompareValidator1" runat="server"   ControlToValidate="UnitPrice"   ErrorMessage="Y

36、ou must enter a valid currency value with   no currency symbols. Also, the value must be greater than   or equal to zero."   Operator="GreaterThanEqual" SetFocusOnError="True"   Type="Currency" Display=&qu

37、ot;Dynamic"   ValueToCompare="0">*</asp:CompareValidator>  </EditItemTemplate>  <ItemStyle HorizontalAlign="Right" />  <ItemTemplate>  <asp:Label ID="Label1" runat="server&quo

38、t;   Text='<%# Bind("UnitPrice", "0:c") %>' />  </ItemTemplate> </asp:TemplateField> </Columns></asp:GridView> <asp:ObjectDataSource ID="ProductsDataSourceDeclarative" runat="server

39、" SelectMethod="GetProducts" TypeName="ProductsBLL" UpdateMethod="UpdateProduct"> <UpdateParameters> <asp:Parameter Name="productName" Type="String" /> <asp:Parameter Name="unitPrice" Type=&qu

40、ot;Decimal" /> <asp:Parameter Name="productID" Type="Int32" /> </UpdateParameters></asp:ObjectDataSource>下一步,为ObjectDataSource控件的Selecting事件创建一个事件处理器:?12345protected void ProductsDataSourceDeclarative_Selecting (object sender, ObjectDataSo

41、urceSelectingEventArgs e) ODSEvents.Text = "- Selecting event fired"我们知道,只有当ObjectDataSource控件从它的相关“源对象”(underlying object)获取数据时才会触发它的Selecting事件。如果ObjectDataSource是从内存检索数据的话,将不会触发Selecting事件.现在,在浏览器里登录该页面,因为我们还没有进行缓存,所以每当你分页、排序、编辑时,页面都会显示文本“Selecting event fired”, 如图8所示:图8:当分页、排序、编辑时

42、都会触发ObjectDataSource的Selecting事件。就像我们在教程使用ObjectDataSource缓存数据里探讨的一样,除了EnableCaching属性以外,ObjectDataSource控件还有SqlCacheDependency property属性,它可以为缓存数据添加一个或更多的SQL cache dependencies.像下面这样:databaseName1:tableName1;databaseName2:tableName2;.其中,databaseName是Web.config文件里<add>元素的name属性指定的数据库名,而tableNa

43、me就是数据库里的一个表。举个例,要创建一个ObjectDataSource,它用SQL cache dependency来缓存数据,当我们指定要用Northwind数据库里的 Products表时,我们将ObjectDataSource的EnableCaching属性设置为true,且SqlCacheDependency属性为“NorthwindDB:Products”.注意:你可以通过设置EnableCaching属性为true来使用一个 SQL cache dependency和基于时间的缓存期(time-based expiry)。CacheDuration对应时间间隔;SqlCach

44、eDependency对应数据库名和表名。不管是缓存到期还是检查系统(polling system)发现“源数据”发生改变,只要其中一个发生, ObjectDataSource 都会将清除其数据。在SqlCacheDependencies.aspx页面里的GridView 控件从2个表获取数据Products 和 Categories (产品的CategoryName列是通过语法 JOIN on Categories来获取的). 因此,我们想指定2个SQL cache dependencies:“NorthwindDB:Products;NorthwindDB:Categories”.图9:设

45、置ObjectDataSource支持缓存,且使用基于表Products 和 Categories的SQL Cache Dependencies设置SQL Cache Dependencies支持缓存后,再次来浏览器里登录页面。最开始,文本“Selecting event fired”依然会出现在页面里,但当进行分页、排序或点击编辑和取消按钮时,文本就消失了。这是因为对数据进行缓存后,其缓存状态一直持续,直到Products 或 Categories表发生了改变,或我们通过GridView对数据进行了更新。做个实验,在第一个浏览器窗口进行分页操作,请注意文本“Selecting event f

46、ired”并没有显现出来。再打开第2个浏览器窗口,导航到页面Basics.aspx页面(/EditInsertDelete/Basics.aspx). 对某个产品的name 或 price进行更新。 再次返回到第一个浏览器窗口,查看下一个页面或进行排序操作或点击某行的编辑按钮,这一次,文本“Selecting event fired又出现了,这是因此“源数据”发生了更改(见图10)。如果文本没有出现,请稍等一下再试一回。我们知道,polling服务每隔设定的pollTime那么多毫秒对Products表进行检查,开是否改动过。因此在源数据的更新和“过时”数据的清除之间有个延迟期。图10:改动P

47、roducts表将导致清除“过时”的Product缓存数据第六步:通过编程的方式处理SqlCacheDependency类在教程在分层架构中缓存数据我们看到了使用单独的缓存层 Caching Layer的好处。在那篇教程,我们创建了一个ProductsCL 类来处理data cache.要在缓存层Caching Layer利用SQL cache dependencies的话,要用到SqlCacheDependency 类。在检测系统(polling system)里,一个SqlCacheDependency对象必须与某个具体的数据库和表挂钩。下面的代码,创建了一个SqlCacheDepende

48、ncy对象,它基于Northwind数据库的Products表:?12Caching.SqlCacheDependency productsTableDependency = new Caching.SqlCacheDependency("NorthwindDB", "Products");上面的2个参数分别对应数据库名和表名。与ObjectDataSource控件的属性SqlCacheDependency类似,数据库名是使用的Web.config.文件里<add> 元素的name属性指定的值,而表名是实际的数据库表名.。要将一个S

49、qlCacheDependency与添加到内存的条目联系起来,可以使用一个重载的接受dependency的Insert方法。下面代码里的SqlCacheDependency基于表Products,且缓存时间未定。换句话说,数据会一直保存在内存,除非内存不足或表Products发生了改变才被清除掉。?1234567Caching.SqlCacheDependency productsTableDependency = new Caching.SqlCacheDependency("NorthwindDB", "Products");Cache.I

50、nsert(key,  value,  productsTableDependency,  System.Web.Caching.Cache.NoAbsoluteExpiration,  System.Web.Caching.Cache.NoSlidingExpiration);目前,缓存层Caching Layer的ProductsCL类从表Products获取数据,缓存时间为60秒。 让我们对其进行更新,使其使用SQL cache dependencies. 类ProductsCL的AddCacheItem方法

51、是用来向内存添加数据的,其当前代码如下:?1234567891011121314private void AddCacheItem(string rawKey, object value) System.Web.Caching.Cache DataCache = HttpRuntime.Cache;  / Make sure MasterCacheKeyArray0 is in the cache DataCacheMasterCacheKeyArray0 = DateTime.Now;  / Add a CacheDependenc

52、y Caching.CacheDependency dependency = new Caching.CacheDependency(null, MasterCacheKeyArray); DataCache.Insert(GetCacheKey(rawKey), value, dependency, DateTime.Now.AddSeconds(CacheDuration), System.Web.Caching.Cache.NoSlidingExpiration);让我们对其进行更新,用一个SqlCacheDependency对象来替换掉

53、MasterCacheKeyArray cache dependency:我们来进行测试。在名为ProductsDeclarative的GridView控件下再添加一个GridView,设置其ID为ProductsProgrammatic,在其智能标里将其绑定到一个名为ProductsDataSourceProgrammatic的新的ObjectDataSource,设置该ObjectDataSource使用ProductsCL类,分别在SELECT 和 UPDATE标签里选GetProducts 和 UpdateProduct方法。图11:设置新ObjectDataSource使用Produ

54、ctsCL类图12:在SELECT标签里选GetProducts方法图13:在UPDATE标签选UpdateProduct方法完成设置后,Visual Studio会自动地为GridView控件添加BoundFields和 CheckBoxFields。就像上面那个GridView控件一样,将ProductName, CategoryName, 和 UnitPrice以外的列都删除掉。在其智能标签里,启用分页、排序、编辑功能。同时,为使GridView控件的编辑功能正常工作,将OldValuesParameterFormatString属性改成默认值0. 或干脆在代码声明里将该属性删除。完成上

55、述修改后,最终的GridView 和 ObjectDataSource的声明代码看起来应该和下面的差不多:?1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253<asp:GridView ID="ProductsProgrammatic" runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID

56、" DataSourceID="ProductsDataSourceProgrammatic" AllowPaging="True" AllowSorting="True"> <Columns> <asp:CommandField ShowEditButton="True" /> <asp:TemplateField HeaderText="Product" SortExpression="

57、ProductName">  <EditItemTemplate>  <asp:TextBox ID="ProductName" runat="server"   Text='<%# Bind("ProductName") %>' />  <asp:RequiredFieldValidator ID="RequiredFieldValidator1"&#

58、160;  ControlToValidate="ProductName" Display="Dynamic"   ErrorMessage="You must provide a name for the product."   SetFocusOnError="True"   runat="server">*</asp:RequiredFieldValidator>

59、  </EditItemTemplate>  <ItemTemplate>  <asp:Label ID="Label2" runat="server"   Text='<%# Bind("ProductName") %>' />  </ItemTemplate> </asp:TemplateField> <asp

60、:BoundField DataField="CategoryName" HeaderText="Category"  ReadOnly="True" SortExpression="CategoryName" /> <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">  <EditItemTemplate> 

61、 $<asp:TextBox ID="UnitPrice" runat="server" Columns="8"   Text='<%# Bind("UnitPrice", "0:N2") %>'></asp:TextBox>  <asp:CompareValidator ID="CompareValidator1" runat="server&qu

62、ot;   ControlToValidate="UnitPrice" Display="Dynamic"   ErrorMessage="You must enter a valid currency value with   no currency symbols. Also, the value must be greater than   or equal to zero."   

63、;Operator="GreaterThanEqual" SetFocusOnError="True"   Type="Currency" ValueToCompare="0">*</asp:CompareValidator>  </EditItemTemplate>  <ItemStyle HorizontalAlign="Right" />  <ItemT

64、emplate>  <asp:Label ID="Label1" runat="server"   Text='<%# Bind("UnitPrice", "0:c") %>' />  </ItemTemplate> </asp:TemplateField> </Columns></asp:GridView> <asp

65、:ObjectDataSource ID="ProductsDataSourceProgrammatic" runat="server" OldValuesParameterFormatString="0" SelectMethod="GetProducts" TypeName="ProductsCL" UpdateMethod="UpdateProduct"> <UpdateParameters> <asp:P

66、arameter Name="productName" Type="String" /> <asp:Parameter Name="unitPrice" Type="Decimal" /> <asp:Parameter Name="productID" Type="Int32" /> </UpdateParameters></asp:ObjectDataSource>要测试位于缓存层的SQL cache dependency,先在ProductCL类的AddCacheItem方法里设置断点(breakpoint),然后

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论