在ASP.NET 2.0中操作数据之五十六:使用ObjectDataSource缓存数据

导言

  就计算机科学而言,caching就是将所需要的数据或信息的备份放在某个地方,便于快速访问的这样一个过程。以数据处理(data-driven)程序为例,程序的大部分时间浪费在数据查询上。要提升这种程序的性能,通常的做法是将查询结果存放在程序的存储器里。

  ASP.NET 2.0提供了各种各样的缓存方式。对web页面和用户控件可以通过output caching进行缓存;同样我们可以通过ObjectDataSource 和SqlDataSource控件,在控件级(control level)对数据进行缓存;同时,ASP.NET的data cache提供了丰富的缓存接口(caching API),供页面开发员通过编程缓存对象。在本文及接下来的3篇文章我们将对ObjectDataSource的缓存属性以及data cache进行考察;我们也将探究如何在启动时对application-wide数据进行缓存,以及通过使用SQL cache dependencies对缓存数据刷新。

主要的缓存要点

  由于缓存通过将数据的副本放置在一个便于快速访问的地方来提高程序的总体性能。由于它仅仅是一个副本,当源数据发生改变时,副本不能同步更新。为此,页面开发员应制定一个标准将其清除出内存,可以使用如下的2种方法之一:

  Time-based标准:向内存添加的条目(item),只能在内存里驻留固定或灵活(sliding)的一段时间。比如,开发者可设定一个时间段,比如60秒,当条目添加到内存后,不管访问它的频率有多高,60秒后就会被清除掉;如果是灵活(sliding)处理的话,当最后一次被访问后,未再次被访问的时间一旦超出60秒,也会被清除掉。

  Dependency-based标准:当向内存添加条目时为其分配一个从属体(dependency),当条目对应的从属体发生改变时将条目清除掉。从属体可以是一个文件;另一个缓存条目;或者干脆是这两者的混合体( combination);当然还可以是SQL cache dependencies,它可以向内存添加条目,当源数据改变时将条目清除掉。我们将在接下来的文章《使用SQL缓存依赖项SqlCacheDependency》里详细考察。

  不管是哪种标准,在条目被清除掉以前,我们都可以对其访问。如果内存达到了它的极限,它会清除掉已有的条目后再添加新的条目。因此,当处理缓存数据时很重要的一点是我们要充分考虑到缓存数据已被清除的可能。在下一篇文章《在分层架构中缓存数据》我们考察采用哪种模式从内存访问数据。

  缓存是提升程序性能的一种较为经济的方法,就像Steven Smith在他的文章《ASP.NET Caching: Techniques and Best Practices:》里阐述的一样:“缓存是获得‘上佳'性能的一种好方法,不需要太多的时间和分析。… 存储器也便宜,要获得你期望的性能,靠缓存技术你需要花30秒;靠优化代码和数据库你可能要几天乃至几周时间…”

  虽然缓存可以显而易见的提升系统性能,但并不是适用于所有的应用程序,比如某些实时(real-time)、频繁更新数据的程序就不适合。
  但是对大部分程序而言,还是适用的。关于ASP.NET 2.0里的缓存的更多背景资料请参考ASP.NET 2.0 QuickStart Tutorials系列的Caching for Performance 部分。

第一步:创建Caching页面

在我们开始以前,首先让我们花些时间来添加包括本篇在内的最近四篇教程需要用到的页面。我们先在项目中新建一个称作Caching的文件夹,接下来,为目录新增以下几个页面,并配置为使用Site.master母板页。

Default.aspx
ObjectDataSource.aspx
FromTheArchitecture.aspx
AtApplicationStartup.aspx
SqlCacheDependencies.aspx


图1:创建相关的ASP.NET页面

像其它文件夹一样,Caching文件夹里的Default.aspx页面将本系列的文章显示出来。记得用户控件SectionLevelTutorialListing.ascx提供该功能,设计模式里将其拖到页面上。


图2:为Default.aspx页面添加用户控件SectionLevelTutorialListing.ascx

最后,将这些页面添加到Web.sitemap文件里,特别的,放在“Working with Binary Data” <siteMapNode>:之后:

<siteMapNode title="Caching" url="~/Caching/Default.aspx"
 description="Learn how to use the caching features of ASP.NET 2.0.">
 <siteMapNode url="~/Caching/ObjectDataSource.aspx"
 title="ObjectDataSource Caching"
 description="Explore how to cache data directly from the
 ObjectDataSource control." />
 <siteMapNode url="~/Caching/FromTheArchitecture.aspx"
 title="Caching in the Architecture"
 description="See how to cache data from within the
 architecture." />
 <siteMapNode url="~/Caching/AtApplicationStartup.aspx"
 title="Caching Data at Application Startup"
 description="Learn how to cache expensive or infrequently-changing
 queries at the start of the application." />
 <siteMapNode url="~/Caching/SqlCacheDependencies.aspx"
 title="Using SQL Cache Dependencies"
 description="Examine how to have data automatically expire from the
 cache when its underlying database data is modified." />
</siteMapNode>

完成Web.sitemap文件的更新后,让我们在浏览器里查看,左边的菜单栏显示caching章节的文章
图3:网站地图Site Map包含了Caching章节的文章

第二步:在Web Page页面里展示产品

  本文考察怎样使用ObjectDataSource控件内置(built-in)的缓存功能。在开始之前,我们首先需要创建一个页面,用一个ObjectDataSource控件调用ProductsBLL class类获取产品信息,再用GridView控件展示出来。

  首先打开Caching文件夹里的ObjectDataSource.aspx页面。从工具箱拖一个GridView控件到页面,设置其ID为Products,再从智能标签里选择将其绑定到一个ObjectDataSource控件,ID为ProductsDataSource。设该ObjectDataSource使用ProductsBLL class类。


图4:设置ObjectDataSource控件使用ProductsBLL Class类

  在本页面,我们要创建一个允许编辑的GridView控件,当ObjectDataSource控件里的缓存数据发生改变时,我们可以通过GridView的界面查看到底会发生什么。在SELECT标签里选择默认的GetProducts()方法, 但是在UPDATE标签里选择接受productName, unitPrice 和productID作为输入参数的UpdateProduct()重载方法。


图5:在UPDATE标签里选择重载的UpdateProduct()方法

  最后,在INSERT和DELETE标签里选择“(None)”,点完成按钮。一旦完成“设置数据源向导”,Visual Studio会将ObjectDataSource控件的OldValuesParameterFormatString属性设置为original_{0}。就像在前面的教程之16章《概述插入、更新和删除数据》里探讨的一样,该属性要么删除掉,要么设置为{0},不然的话更新操作会报错。

  此外,完成向导后,Visual Studio会将产品的所有数据列添加到GridView控件,将除了ProductName, CategoryName和UnitPrice之外的所有绑定列(BoundFields)删除。然后,分别将上述3列的HeaderText属性改为Product”, “Category”和“Price”。由于ProductName是必需的,将ProductName列转变成模板列(TemplateField),在EditItemTemplate里添加一个RequiredFieldValidator控件;同样的,将UnitPrice列也转换成模板列,并添加一个CompareValidator控件,确保用户输入的是大于或等于0的有效的货币值。除此以外,你还可以作一些界面上的改进,比如使UnitPrice值居中,或分别对UnitPrice的只读和编辑界面作一些格式化的处理。

  在GridView的智能标签里点相关项启动编辑、分页、排序功能。

  注意:想回顾怎样自定义GridView的编辑界面吗?请参考前面的文章之20《定制数据修改界面》


图6:启用GridView的编辑、排序、分页功能。

完成GridView的修改后,GridView 和 ObjectDataSource的代码声明看起来像下面这样:

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False"
 DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
 AllowPaging="True" AllowSorting="True">
 <Columns>
 <asp:CommandField ShowEditButton="True" />
 <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
 <EditItemTemplate>
 <asp:TextBox ID="ProductName" runat="server"
 Text='<%# Bind("ProductName") %>'></asp:TextBox>
 <asp:RequiredFieldValidator
 ID="RequiredFieldValidator1" Display="Dynamic"
 ControlToValidate="ProductName" SetFocusOnError="True"
 ErrorMessage="You must provide a name for the product."
 runat="server">*</asp:RequiredFieldValidator>
 </EditItemTemplate>
 <ItemTemplate>
 <asp:Label ID="Label2" runat="server"
 Text='<%# Bind("ProductName") %>'></asp:Label>
 </ItemTemplate>
 </asp:TemplateField>
 <asp:BoundField DataField="CategoryName" HeaderText="Category"
 ReadOnly="True" SortExpression="CategoryName" />
 <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
 <EditItemTemplate>
 $<asp:TextBox ID="UnitPrice" runat="server" Columns="8"
 Text='<%# Bind("UnitPrice", "{0:N2}") %>'></asp:TextBox>
 <asp:CompareValidator ID="CompareValidator1"
 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."
 Operator="GreaterThanEqual" SetFocusOnError="True"
 Type="Currency" runat="server"
 ValueToCompare="0">*</asp:CompareValidator>
 </EditItemTemplate>
 <ItemStyle HorizontalAlign="Right" />
 <ItemTemplate>
 <asp:Label ID="Label1" runat="server"
 Text='<%# Bind("UnitPrice", "{0:c}") %>' />
 </ItemTemplate>
 </asp:TemplateField>
 </Columns>
</asp:GridView>

<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
 OldValuesParameterFormatString="{0}" SelectMethod="GetProducts"
 TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
 <UpdateParameters>
 <asp:Parameter Name="productName" Type="String" />
 <asp:Parameter Name="unitPrice" Type="Decimal" />
 <asp:Parameter Name="productID" Type="Int32" />
 </UpdateParameters>
</asp:ObjectDataSource>

如图7所示,GridView列出了每个产品的name, category和price信息。花几分钟测试页面—对结果排序,查看分页,编辑某条记录。


图7:显示每条记录的Name, Category和Price信息

第三步:考察ObjectDataSource如何请求数据

  ID为Products的GridView通过调用名为ProductsDataSource的ObjectDataSource的Select()方法检索数据并将它显示出来。该ObjectDataSource创建业务逻辑层的ProductsBLL class类的一个实例并调用它的GetProducts()方法,该方法又调用数据访问层ProductsTableAdapter的GetProducts()方法。数据访问层连接到数据库Northwind,并执行已设置好了的SELECT查询。查询数据以NorthwindDataTable的形式返回到数据访问层,该DataTable对象再依次传回到业务逻辑层,ObjectDataSource、GridView控件。GridView控件为DataTable里的每一数据行(DataRow)创建一个GridViewRow对象,每个GridViewRow对象最终被编译为HTML返回到客户端,呈现在访问者的浏览器里。

  任何时候,当GridView控件需要绑定时,按上述的事件发生顺序执行。比如,首次登录页面;将数据从一个页面传递到另一个页面;在GridView里排序;通过GridView内建的编辑或删除界面改动数据。当GridView的视图(view sta被设为disabled时,每次页面回传时也会对GridView重新绑定;当然我们可以显式地调用DataBind()方法来对GridView实施绑定。

  为了更清除地揭示从数据库检索数据的频率,我们显示一个消息,提示在某时程序在检索数据。为此,在GridView控件上添加一个ID为ODSEvents的Label控件,清除其Text属性,将其EnableViewState属性设置为false。在Label控件下面再添加一个Button控件,设其Text属性为“Postback”.


图8:在GridView上添加Label 和 Button控件

在整个数据检索过程中,首先触发ObjectDataSource的Selecting事件,并调用其对应的已设置好的方法。为该事件创建一个事件处理器,添加如下的代码:

protected void ProductsDataSource_Selecting(object sender,
 ObjectDataSourceSelectingEventArgs e)
{
 ODSEvents.Text = "-- Selecting event fired";
}

  每当ObjectDataSource开始检索数据时,Label控件都会显示文本“Selecting event fired”.

  在浏览器访问该页面。当首次登录时,文本“Selecting event fired”就会显示出来。点“Postback”按钮时,我们注意到文本消失了(前提是你将GridView的EnableViewState属性设置为默认值true)。这是因为当页面回传时,GridView通过它的视图状态(view state)载入数据进行重建(reconstructed),因此不再需要通过ObjectDataSource检索数据库来得到数据进行重建。然而,排序、分页、编辑等都会促使GridView重新绑定到数据源,因此,文本“Selecting event fired”又出现了。


图9:当GridView重新绑定到数据源时,显示文本“Selecting event fired”


图10:点“Postback” 按钮导致GridView从视图状态“View State”获取数据

  每次分页、排序时都需要从数据库检索数据,这看起来有点浪费资源。即便GridView不支持排序和分页,任何人每次第一次登录页面时都需要从数据库检索数据(如果将view state设置为disabled的话,每次页面回转也会检索数据)。如果GridView对所有用户显示的数据都是一样话,那么额外的数据库查询是浪费。我们可以对GetProducts()方法返回的数据进行缓存,再将GridView绑定到这些缓存数据。

第四步:用ObjectDataSource缓存数据

仅仅简单的设置某些属性,我们就可以让ObjectDataSource对它的检索数据自动的进行缓存。以下总结了ObjectDataSource控件的与缓存相关的属性:

EnableCaching—必须设置为true,默认为false.

CacheDuration—缓存时间,以秒为单位。默认为0,只有当EnableCaching属性设置为true,且CacheDuration设为大于0的值时ObjectDataSource控件才会缓存数据。

CacheExpirationPolicy—可设置为Absolute 或 Sliding。如果为Absolute,当它设为多少秒时,ObjectDataSource就会对检索的数据缓存多少秒;如果为Sliding,当它设为多少秒时,一旦超过那么多秒没有对缓存数据进行访问,就终止缓存。默认为Absolute。

CacheKeyDependency—用该属性将ObjectDataSource的缓存条目(entry)与现有的缓存从属体关联起来。利用可以它将缓存条目提前从内存清除掉。绝大多数情况下用该属性把SQL cache dependency与ObjectDataSource的缓存关联起来。这个话题我们将在后面的教程《使用SQL缓存依赖项SqlCacheDependency》考察。

让我们设置ID为ProductsDataSource的ObjectDataSource 的数据缓存时间为30秒。设其EnableCaching属性为true;设其CacheDuration属性为30;CacheExpirationPolicy属性为默认的Absolute。


图11:设置ObjectDataSource的缓存时间为30秒

  保存你的设置,并在浏览器里查看。当你第一次登录页面时,文本“Selecting event fired”会显示出来,因为原始数据还未缓存。但你点“Postback”按钮,或进行分页,排序,或点编辑、取消按钮时,文本“Selecting event fired”就不会显示出来了。原因是只有当ObjectDataSource控件检索数据时才会触发Selecting事件;如果ObjectDataSource控件是从缓存里面获取数据的话就不会触发Selecting事件。

  过了30秒后,数据将从内存清除;或者调用ObjectDataSource控件的Insert, Update,或Delete方法的话数据也会被清除掉。因此,过了30秒后或点击“Update”按钮,编辑,取消按钮,或排序、分页的话就会促使ObjectDataSource检索数据,触发Selecting事件,文本“Selecting event fired”又会显示出来。最后,再对检索得到的数据进行缓存。

  注意:如果你看到文本“Selecting event fired”频繁的出现,很可能是内存容量太小。如果没有足够的容量,ObjectDataSource添加到内存的数据可能被清除掉了。如果ObjectDataSource没有或者只是偶尔地对数据缓存,请关闭一些应用程序来释放掉内存,然后再试一次。

  图12揭示了ObjectDataSource的缓存流程。当文本“Selecting event fired”出现在屏幕上时,那是因为数据没有在缓存里找到,必须进行相关检索。当文本消失时,那是因为数据进行了缓存。当从缓存得到了所需的数据时,没有任何数据查询执行。


图12:ObjectDataSource在Data Cache里存储和获取数据

  每一个ASP.NET应用程序有它自己的数据缓存实例,所有的页面和用户都可以进行访问。那意味着对于ObjectDataSource控件缓存的数据,所有登录该页面的用户都可以访问。来做个验证,在一个浏览器里打开ObjectDataSource.aspx页面,当第一次登录该页面时,文本“Selecting event fired”显现出来(假定前面测试时缓存的数据到此时已经被清除掉了)。再开第二个浏览器,将第一个浏览器里的URL地址拷贝、粘贴过来。在第二个浏览器里,文本“Selecting event fired”并没有显示出来,因为它使用的是第一个浏览器页面缓存的数据。

  当向内存添加检索数据时,ObjectDataSource要用到一个叫cache key的值,该值包括:CacheDuration 和 CacheExpirationPolicy属性的值;ObjectDataSource调用的业务对象的类型(type),它由TypeName 属性指定(比如:ProductsBLL);SelectMethod 属性的值,以及SelectParameters参数集里参数的name 和 values;StartRowIndex 和 MaximumRows属性的值,它用来执行用户自定义分页(custom paging)。

  将这些属性值组合在一起构成cache key值是为了对每一个缓存条目提供唯一的标识值。比如,在前面的教程里,我们使用ProductsBLL类的GetProductsByCategoryID(categoryID)方法来获取某个指定类的所有产品。假如一个用户在页面查看饮料类(其CategoryID值为1)的产品信息,如果ObjectDataSource控件在进行数据缓存时忽略SelectParameters的值,当另一个用户登录页面查看调味品类的产品信息时,恰好饮料类产品信息正好缓存在内存里,第二个用户将会看到饮料类的产品信息,而非他想要的调味品类的产品信息。所以,当cache key值包含electParameters的值的话,ObjectDataSource缓存数据的时候就可以将调味品类和饮料类区分开来。

数据更新不同步(Stale Data)问题

  当调用ObjectDataSource控件的Insert, Update和 Delete其中一个方法时,它都会将缓存条目从内存清除掉。这样做的好处在于当从页面修改数据时将缓存的旧数据清除掉。然而,ObjectDataSource还是可能有将“未更新数据”(也就是源数据已经发生改变,而缓存的数据没同步更新)显示出来的情况。最简单的例子是直接从数据库修改数据,比如某个数据库管理员运行一个脚本,修改数据库里的某些记录。

  在此,我们探讨一种微妙的情况。虽然调用ObjectDataSource的数据修改方法时它会将缓存数据清除掉,但清除的是那些与ObjectDataSource的“属性组合值”(combination of property)相匹配的缓存条目(比如CacheDuration, TypeName, SelectMethod等)。假如你有2个ObjectDataSources控件,它们更新相同的数据,当使用不同的SelectMethods 或 SelectParameters,当第一个ObjectDataSources控件更新某一行记录而清除该行对应的缓存数据时,第二个ObjectDataSources控件仍然使用该行对应的缓存数据。我们来做个验证,创建一个页面,包含可编辑的GridView控件,其对应的ObjectDataSource控件设置为使用缓存,且调用ProductsBLL类的GetProducts()方法来获取数据。在本页(或另外创建一个页面)再添加GridView 和ObjectDataSource控件,但是设置第二个ObjectDataSource控件调用GetProductsByCategoryID(categoryID)方法。由于这2个ObjectDataSource控件的SelectMethod属性不同,因此它们各自有各自不同的缓存值。如果你在第一个GridView控件里编辑某个产品,然后在第二个GridView控件里重新绑定数据(比如分页、排序等),我们在第二个GridView控件里看到该产品的值依然是“老的缓存数据”(而并不是第一个GridView控件修改后的值)

  简而言之,如果你乐于使用“老的缓存数据”,那只有使用基于时间的缓存时间值(time-based expiries,也就是设置具体的缓存时间长度),如果对数据及时更新要求很高的话,将缓存时间设短点。如果不允许使用“老的缓存数据”的话,要么放弃缓存,要么使用SQL cache dependencies(你可以认为它是你缓存的数据库数据)。我们将在后面探讨SQL cache dependencies。

总结:

  在本文我们考察了ObjectDataSource内建的缓存功能。仅仅设置很少的属性,我们可以将ObjectDataSource调用SelectMethod方法得到的数据进行缓存。其CacheDuration 和 CacheExpirationPolicy属性指定了缓存的时间和类型(absolute或sliding)。而CacheKeyDependency属性将ObjectDataSource的缓存实体与现有的缓存从属体(cache dependency)关联起来,一般是SQL cache dependencies。

  因为ObjectDataSource只是简单地进行数据缓存,我们可以通过编程实现ObjectDataSource内建的这种功能。不过在表现层这样做没有意义,因为ObjectDataSource控件提供了该功能。不过我们可以在体系结构的其它层次实现缓存功能。为此,我们需要一个逻辑,它与ObjectDataSource调用的相同。在下一篇文章我们将考察如何在体系结构内部编程处理数据缓存。

  祝编程快乐!

作者简介

  本系列教程作者 Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用 微软Web技术。大家可以点击查看全部教程《[翻译]Scott Mitchell 的ASP.NET 2.0数据教程》,希望对大家的学习ASP.NET有所帮助。

(0)

相关推荐

  • 在ASP.NET 2.0中操作数据之六十二:GridView批量更新数据

    导言: 在前面的教程,我们对数据访问层进行扩展以支持数据库事务.数据库事务确保一系列的操作要么都成功,要么都失败.本文我们将注意力转到创建一个批更新数据界面. 在本文,我们将创建一个GridView控件,里面的每一行记录都可以进行编辑(见图1),因此我们没有必要多添加一列来包含Edit, Update,和Cancel按钮,而是在页面包含2个"Update Products"按钮,被点击时,遍历所有的产品并对数据库进行更新.让我们开始吧. 图1:GridView控件里的每一行记录都可以编

  • 在ASP.NET 2.0中操作数据之六十三:GridView实现批量删除数据

    导言: 在前面的教程,我们用GridView创建了一个批编辑界面.在用户需要一次性编辑多条记录的情况下,批编辑界面很有用.同理,当用户需要同时删除多条记录时,该技术也很有用. 如果你使用过邮件系统的话,你应该对这种最常见的批删除界面很熟悉:界面里每一行都包含一个checkbox,此外,还有一个"Delete All Checked Items"按钮(如图1).本教程比较短,因为我们在前面的教程已经完成大体的框架,在前面的第50章<为GridView控件添加Checkbox>

  • 在ASP.NET 2.0中操作数据之五十七:在分层架构中缓存数据

    导言: 正如前面章节所言,缓存ObjectDataSource的数据只需要简单的设置一些属性.然而,它是在表现层对数据缓存,这就与ASP.NET page页面缓存策略(caching policies)紧密的耦合(tightly couples)起来.我们对体系机构分层的原因之一便是打破这种耦合.拿业务逻辑层为例,将业务逻辑从ASP.NET页面脱离出来:而数据访问层将数据访问的细节ASP.NET页面脱离出来.从某种意义来说,将业务逻辑和数据访问细节脱离出来是首先,这样的话使系统更易读.易维护.易

  • 在ASP.NET 2.0中操作数据之五十九:使用SQL缓存依赖项SqlCacheDependency

    导言: 在56和57章探讨的缓存技术使用的是基于时间的缓存周期,当过了某段时间后便将缓存数据从内存清除.当设置缓存时间为x秒时,数据在x秒内都是"新"的.当然,就像在60章谈到的那样,对静态数据来说,x可延伸到web应用程序的整个生命周期(lifetime). 当缓存数据时,基于时间周期的技术因为其易用性而常常被采用,不过又常常不那么完美.理想的状态是这样的:数据库数据还是应缓存在内存,直到源数据(underlying data)发生改变时才从内存清除.这样的话可以最大化的获取缓存带来

  • 在ASP.NET 2.0中操作数据之六十一:在事务里对数据库修改进行封装

    导言: 正如我们在第16章<概述插入.更新和删除数据>里探讨的那样,GridView控件内建的功能支持对每行数据的编辑和删除功能,你只需要稍稍动一下鼠标就可以创建丰富的数据修改界面而不用写一行代码.但是,在某些情况下,这还不够,我们需要让用户能够成批地处理数据. 比如,很多基于web(web-based)的电子邮件客户端,将所有邮件出来,每条邮件除了包含邮件信息(主题.发送者等)外,还包含一个checkbox控件.这些界面允许用户同时删除多个邮件,用户只需要选中邮件,再点"删除所选邮

  • 在ASP.NET 2.0中操作数据之六十:创建一个自定义的Database-Driven Site Map Provider

    导言: ASP.NET 2.0的网站地图(site map)功能允许页面开发者在一些持久介质(persistent medium),比如一个XML文件里,自己定义一个web程序的site map.一旦定义了之后,我们可以通过System.Web命名空间的SiteMap class类或某个Web导航控件,比如SiteMapPath, Menu, 或TreeView来对其进行访问.site map系统使用的是provider model模式,所以可以创建不同的site map,并将其应用到一个web

  • 在ASP.NET 2.0中操作数据之六十六:在TableAdapters中使用现有的存储过程

    导言: 在前面的文章里我们考察了如何让TableAdapters向导自动的创建存储过程.而在本文,我们将考察如何让TableAdapter使用现有的存储过程.由于Northwind数据库现有的存储过程很少,我们也需要考察如何在Visual Studio环境里手动向数据库添加新的存储过程. 注意:在第61章<在事务里对数据库修改进行封装>里我们向TableAdapter添加了一些方法以支持事务(比如 (BeginTransaction, CommitTransaction等).我们可以在不修改数

  • 在ASP.NET 2.0中操作数据之六十五:在TableAdapters中创建新的存储过程

    导言: 本教程的Data Access Layer (DAL)使用的是类型化的数据集(Typed DataSets).就像我们在第一章<创建一个数据访问层>里探讨的一样,该类型化的数据集由强类型的DataTable和TableAdapter构成.DataTable描绘的是系统里的逻辑实体而TableAdapter引用相关数据库执行数据访问,包括对DataTable填充数据.执行返回标量数据(scalar data)的请求.添加,更新,删除数据库里的记录等. TableAdapter执行的SQL

  • 在ASP.NET 2.0中操作数据之六十四:GridView批量添加数据

    导言: 在前面的第62章<GridView批量更新数据>里,我们用GridView控件里定制了一个批编辑界面,同样的我们也可以定制一个批添加界面.假设有这种情况,我们接受一批从Tokyo(东京)发过来的货物:6种不同的tea 和 coffee,如果用户在一个DetailsView控件里一次输入一个产品,他将会重复的输入很多相同的值,比如相同的种类(Beverages),相同的供应商(Tokyo Traders),相同的discontinued值(False),以及相同的order值(0).重复

  • 在ASP.NET 2.0中操作数据之五十八:在程序启动阶段缓存数据

    导言: 前面2章考察了在表现层和缓存层缓存数据.在第56章,我们探讨了在表现层设置ObjectDataSource的相关cache属性来缓存数据.在第57章,我们探讨了创建一个单独的分开的缓存层.这2章都是采用"应激装载"(reactive loading)的模式来缓存数据.该模式下,每次请求数据时,系统先检查其是否在内存,如果没有,则从数据源--比如数据库,来获取数据,然后将其存储在内存里.该模式的优势在于执行起来很容易:而缺点之一在于应"请求"(requests

随机推荐