ASP.NET 2.0 中的数据源控件


  本文标签:.net ASP ASP.NET

  

  ASP.NET 2.0 引入了一系列可以改善数据访问的新工具,包括几个数据源和数据绑定控件  。新增种类的数据源控件可以消除 ASP.NET 1.x 中要求的大量重复性代码  。例如,您可以很容易地将 SQL 语句或存储过程与数据源控件相关联,并且将它们绑定到数据绑定控件  。更令人感到印象深刻的是,通过 ObjectDataSource 控件可以简化开发和减少代码,并且仍然可以在 n 层体系结构的不同层中抽象业务和数据访问逻辑  。

  在 .NET 问世以前,用传统的 ASP 生成数据网格通常需要编写大量的代码,以便在遍历 ADO 记录集的同时即时生成 HTML 表  。ASP.NET 1.x 通过允许您将基于 XML 的 DataSet 绑定到 ASP.NET DataGrid 控件,从而使该类型的开发变得更加容易  。这就减少了生成网格所必需的代码  。但是,传统的 ASP 和 ASP.NET 1.x 都要求代码实现分页、排序、编辑和行选择功能  。通过 ASP.NET 2.0 中的改进功能,可以显著减少这些代码的数量,以产生带有完整分页、排序和编辑功能并填充了数据的网格  。

  在这一期的 Data Points 中,我将首先演示通过 ASP.NET 2.0 并使用 SqlDataSource 和一些新的数据绑定控件开发 Web 应用程序是多么容易  。请注意,我在此使用的是 Beta 1 版本  。

  大多数企业应用程序都是在多层体系结构之上生成的,该体系结构有一个用于存放业务逻辑的中间层,以及一个使用一个或多个后端数据库的数据访问层  。我将讨论 ObjectDataSource 可以多么理想地与现有的多层组件集成  。通过将 ObjectDataSource 控件链接到业务对象,您可以充分利用现有的多层体系结构来生成完善的 Web UI,并且能够显著减少代码  。 ObjectDataSource 控件还包含一些特殊的属性,使您可以绑定到 ASP.NET 2.0 和 ADO.NET 2.0 中新近增强的强类型 DataSet 和数据组件  。 ASP.NET 2.0 中的其他新功能和改进包括新增的双向绑定表达式、增强的缓存,以及几个新增的可以数据绑定到新的数据源控件的 ASP.NET 2.0 控件  。

数据绑定控件

  要使用数据源控件,必须具有一个用来将它们绑定到的数据绑定控件  。在 ASP.NET 2.0 中有几个新的数据绑定控件,包括 GridView、DetailsView 和 FormView 控件  。如果您喜欢 ASP.NET 1.x DataGrid 控件,那么您也会喜欢 ASP.NET 2.0 GridView 控件  。GridView 在本质上类似于 DataGrid,因为它可以绑定到新的数据源控件,并且可以用来实现排序、编辑和分页 — 它们需要的代码都比 DataGrid 少得多(有关 GridView 的详细信息,请参阅 Dino Esposito 在 MSDN®Magazine 的2004年8月中发表的文章)  。

  要将 GridView 绑定到数据源控件,需要将 GridView 的 DataSourceID 属性设置为数据源控件的 ID  。还可以设置 GridView 的其他几个属性来增强外观和用户交互(我将在稍后的示例中加以演示):


  其他控件(例如,DropDownList)也可以绑定到数据源控件  。例如,DropDownList 控件可以绑定到检索雇员列表的 SqlDataSource 控件  。雇员的全名可以显示在 DropDownList 中,而 EmployeeID 可以作为控件的基础数据值字段绑定到该控件  。以下示例定义了一个 DropDownList,它将显示可供选择的客户名称的列表  。客户数据被绑定到一个名为 sdsCustomerDataSource 的 SqlDataSource 控件,该控件可获得客户的 CompanyName 和 CustomerID 字段的列表:



  在 ASP.NET 2.0 中,将控件绑定到数据源控件非常简单,并且不需要任何处于代码隐藏中的代码  。但是,如果您愿意,仍然可以编写代码以显式绑定到控件  。实际上,数据绑定控件的数据源和 DataMember 属性与 ASP.NET 1.x 相比已经得到了改进  。

数据源控件

  在 ASP.NET 2.0 中有几个新的数据源控件,例如,SqlDataSource、ObjectDataSource、XmlDataSource、AccessDataSource 和 SiteMapDataSource(如图 1 所示)  。它们全都可以用来从它们各自类型的数据源中检索数据,并且可以绑定到各种数据绑定控件  。数据源控件减少了为检索和绑定数据甚至对数据进行排序、分页或编辑而需要编写的自定义代码的数量  。

  每个数据源控件都具有类似的属性,以便可以与其各自的数据源进行交互  。生成 SiteMapDataSource 和 XmlDataSource 是为了检索分层数据,而生成其他数据源控件是为了检索带有列和行的基于集合的数据  。

  专门生成 AccessDataSource 以便从 Access 数据库中检索数据  。SqlDataSource 听起来好像只能使用 SQL Server?,但实际情况不是这样的  。它实际上可以用来从任何 OLE DB 或符合 ODBC 的数据源中检索数据  。

命令类型和参数

  SqlDataSource 控件具有四个命令属性,您可以设置这些属性以告诉 SqlDataSource 如何获得、插入、更新和删除它的数据  。可以将 SelectCommand 属性设置为 SQL 语句或存储过程  。在任何一种情况下,都可以根据需要传入参数  。InsertCommand、UpdateCommand 和 DeleteCommand 属性用于告诉 SqlDataSource 使用哪些 SQL 语句(或存储过程)来修改基础数据库中的数据  。图 2 中的代码示例显示了一个 SqlDataSource,它将它的 SelectCommand 和 UpdateCommand 属性设置为参数化的 SQL 语句  。请注意,UpdateParameters 使用 Parameter 元素来指示要用于参数的字段的名称和数据类型  。在将 GridView 绑定到该 SqlDataSource 以后,这些 UpdateParameters 值就被绑定到受影响行的具有相同名称的列  。

  您自己对此进行试验的最简单方式是,在 Visual Studio? 2005 中创建一个 Web 窗体,连接到服务器资源管理器窗口中的本地 SQL Server Northwind 数据库,然后将一个表拖到该 Web 窗体  。这会自动创建一个 SqlDataSource 控件以及一个 GridView  。Visual Studio 会自动将 SqlDataSource 控件的 ProviderName 和 ConnectionString 属性设置为 SQL Server Northwind 数据库  。而且,所有四个命令属性都将被设置为适当的 SQL 语句  。然后,您为编辑该 Web 窗体而必须完成的所有工作就是,使用智能标记来选中“Enable Editing”复选框(参见图 3)  。

us0501DataPointsfig03

图 3 GridView设置


  数据源控件还可以使用来自其他控件的参数  。例如,数据源控件可以检索给定客户的所有订单  。在这种情况下,CustomerID 可以是传递给 SqlDataSource 控件的 SelectCommand 属性的 SQL 语句或存储过程的参数  。还可以从其他控件(例如,DropDownList)检索 CustomerID,并将其直接传递到 SqlDataSource 控件的 SQL SelectCommand 中  。

  您可以将控件的值直接链接到 SqlDataSource 控件的任一 SQL 语句(SelectCommand、InsertCommand、UpdateCommand 或 DeleteCommand)的参数,还可以指定究竟要将控件的哪个属性用于该参数  。例如,如果您在上一个示例中不需要 DropDownList 的默认属性,而是需要它的 DataTextField,则可以将 ControlParameter 的 PropertyName 属性设置为 DataTextField  。

  除了 ControlParameter 以外,还可以将其他参数类型用于数据源控件  。如果您要使用新的 ASP.NET 个性化功能,则可以使用 ProfileParameter 从配置文件对象中检索参数的值  。接下来,还有几个从标准 Request 对象的集合中检索它们的数据的参数对象类型  。例如,CookieParameter 可以用来从 Cookie 中检索参数的值  。QueryStringParameter 从任意请求字符串变量中获得它的值,而 FormParameter 从 HTML 窗体的输入字段中获得它的值  。最后,SessionParameter 可以用来从会话变量中检索它的值  。这些类型的参数为数据源控件提供了多个有关如何设置它们的参数值的选项  。

SqlDataSource 示例

  既然我已经完成了概述,那么我将对使用 SqlDataSource 和 ObjectDataSource 来检索和修改数据进行一下对比  。SqlDataSource 控件(它使用 ADO.NET 2.0 DbProviderFactory 对象)具有将它直接链接到 OLE DB 或 ODBC 数据源的属性  。当加载包含链接到 SqlDataSource 的数据绑定控件的 ASP.NET 页时,SqlDataSource 直接与基础数据库进行通信  。因而,SqlDataSourceData 源控件不与现有的业务对象集成  。

  为了查看 SqlDataSource 是如何操作的,让我们先观察一下 Orders_SDS.aspx 页(参见图 4)  。有一个 DropDownList 控件,它绑定到一个从 Northwind 数据库中检索客户列表的 SqlDataSource 源控件  。


图 4 通过 SqlDataSource 检索客户


  还有另外一个名为 sdsOrdersDataSource 的 SqlDataSource,它用于检索选定客户的所有订单  。图 5 中的代码(摘自 Orders_SDS.aspx — 它可在下载中得到)显示了两个 SqlDataSource 控件和这个 DropDownList  。请注意,sdsOrdersDataSource SqlDataSource 控件使用 DropDownList 的选定值作为其存储过程的参数(prGet_Orders 的参数)  。

  ProviderName 和 ConnectionString 属性的组合告诉 SqlDataSource 控件从哪个数据存储中获得数据  。尽管这些属性使 SqlDataSource 成为检索和修改数据的简单解决方案,但遗憾的是,它们在表示层的 ASPX 文件中公开了数据库连接字符串以及 SQL 语句或存储过程  。这通常不是一个好主意  。将该数据以加密形式存储在配置储存库(如配置文件或注册表)中要安全得多  。

  图 4 显示了编辑模式下的 Orders_SDS.aspx 页  。分页由 GridView 自动实现(通过将 GridView AllowPaging 属性设置为 true,并将 PageSize 属性设置为期望的大小,如 10)  。这将告诉网格将其中的行分页,并且在“下一页”或“上一页”链接被单击时自动重新加载网格和页  。GridView 使用 TextBox 控件显示选定行的可编辑列  。数据绑定列是通过 asp:BoundField 或 TemplateField 元素定义的  。通过设置 DataField 属性,可以将 BoundField 绑定到 GridView 的关联数据源:


  这将告诉 GridView 控件,当它处于查看模式时,应该在 span 元素中显示 ShipCity 值  。当 GridView 处于编辑模式时,选定行中的这一列将在适当的 HTML 元素中显示  。在这种情况下,HTML 元素为 TextBox,因为它是一个字符串值  。该元素是基于绑定列的数据类型选择的  。例如,如果该列在 SQL Server 中被定义为位,则将使用 CheckBox 控件在编辑模式下显示该列  。

  TemplateField 元素在绑定列的行为方式方面提供了更大的灵活性  。请观察以下摘自 Orders_SDS.aspx 页的代码示例:

    
        >
    
    
        >
    

 

  当 GridView 处于查看模式时,它使用 TemplateColumn 在 Label 控件中显示 OrderDate 列;当 GridView 处于编辑模式时,它使用 TemplateColumn 在 TextBox 控件中显示 OrderDate 列  。您还可以使用 FooterTemplate 来告诉 Template 列在页脚中以不同的方式显示该列  。还可以使用 HeaderTemplate、AlternatingItemTemplate 甚至 InsertItemTemplate  。还请注意 ASP.NET 2.0 中引入的简化的绑定语法  。OrderDate 的值是通过调用 Bind 表达式并向它传递 GridView 的关联数据源中列的名称和一个可选的数据格式字符串表达式来设置的  。在该示例中,我使用了表示短日期的数据格式字符串  。这些属性都可以通过可借助于 Visual Studio 2005 中的新增智能标记功能访问的属性来轻松设置(参见图 6)  。

ObjectDataSource

  GridView 和其他数据绑定控件的最出色的功能之一是,在设置了它们以后,只需更改单个属性,就可以将它们绑定到 ObjectDataSource 控件或 SqlDataSource 控件  。例如,您必须完成的所有工作就是创建一个新的 ObjectDataSource 控件,并将 GridView 的 DataSourceID 属性更改为这个新的 ObjectDataSource 控件的 ID  。

  与 SqlDataSource 不同的是,ObjectDataSource 控件使您可以从 ASPX 页和表示层中抽象出特定于数据库的设置,并将它们移至多层体系结构中的较低层(参见图 7)  。例如,SqlDataSource 控件的 ConnectionString、ProviderName 和 SelectCommand 属性在 ObjectDataSource 控件中不存在  。相反,它们被替换为告诉 ObjectDataSource 控件实例化哪个业务类以及使用哪个方法来检索或修改数据的其他属性  。


图 7

  要设置 ObjectDataSource 控件以访问另一个层的业务类及其方法,必须首先将 ObjectDataSource 控件的 TypeName 属性设置为该业务类的名称(如 TypeName="MSDN2005Jan_BLL.Orders")  。然后,将 SelectMethod 属性设置为该业务类中将用来检索数据源数据的方法的名称  。该业务类的方法必须返回一个可枚举的列表,例如,集合、数组、DataSet 或 DataReader  。为了让该方案能够工作,ObjectDataSource 必须能够执行指定的方法  。如果它是静态方法,则不需要完成任何特殊的工作  。如果该方法是实例方法,则 ObjectDataSource 必须能够创建该类的实例  。要达到该目的,最简单的方法是将该业务类编写为包含默认的构造函数  。另外,还可以处理 ObjectDataSource 的 ObjectCreating 事件,它使您可以用所需的任何构造函数来实例化该对象,然后将该对象实例传递给数据源控件  。

  图 8 中的代码示例(摘自同样包含在下载中的 Orders.aspx)显示了两个 ObjectDataSource 控件(它们替换了上一个示例中使用的两个 SqlDataSouce 控件)  。odsOrdersDataSource 使用 MSDN2005Jan_BLL.Orders 类和它的 GetData 方法来检索它的订单列表  。在该示例中,Orders 类中的 GetData 方法只是创建名为 OrdersDataSet 的强类型 DataSet 的实例及其相关的名为 OrdersTableAdapter 的适配器  。然后,它调用 Fill 方法并返回强类型的 DataSet:

public OrdersDataSet GetData(string CustomerID)
{
    OrdersDataSet oDs = new OrdersDataSet();
    OrdersTableAdapter oDa = new OrdersTableAdapter();
    oDa.Fill(oDs, CustomerID);
    return oDs;
}

  请注意,GetData 方法还接受由 ObjectDataSource 控件的 SelectParameter 属性传入的 CustomerID 参数  。UpdateData 方法的参数也是从图 8中所示的 UpdateParameters 属性所指示的 ObjectDataSource 传入的  。以下为 Orders 类的 UpdateData 方法的签名:

public void UpdateData(int OrderID, DateTime OrderDate, 
    string ShipCity, string ShipCountry)

  UpdateData 方法的参数的名称和数据类型必须与 ObjectDataSource 控件中更新参数的名称和数据类型相匹配  。数据源控件不能使用批处理更新,因此不能一次性地将多个行传递给更新方法  。相反,必须将每个值作为单个参数传递给更新方法  。除了 SelectMethod 和 UpdateMethod 属性以外,ObjectDataSource 控件还具有 DeleteMethod 和 InsertMethod 属性  。

增强的强类型DataSet

  上一个示例演示了如何将 GridView 绑定到 ObjectDataSource 控件以链接到业务层的类,因此您可以通过该类的方法来检索和更新数据  。如果您具有现有的业务层逻辑和多层体系结构,则该示例可以很好地工作  。它还可以调用 Web 服务客户端代理的方法,或其他任何遵循类和方法要求的引用类的方法  。

  我故意将上个示例的一个方面延迟到现在才加以讨论,那就是强类型 DataSet  。使用 Visual Studio 2005 中的向导,您还可以直接在类型化的 DataSet 类中定义方法,以便选择、插入、更新和删除数据  。因而,您可以避免直接在业务层或数据访问层中编写任何 ADO.NET 代码,而是使用向导直接将 ADO.NET 逻辑添加到类型化的 DataSet 中  。

  您不必检索类型化的 DataSet,但是在这种情况下它是有价值的 — 这要归功于它的一些新的增强功能  。类型化的 DataSet 创建了一个默认的 Fill 方法,该方法被追加到类型化 DataSet 的定义中的 TableAdapter 类  。可以将这一可选的 TableAdapter 类设置为存储连接字符串以及存储过程或 SQL 语句,以便在数据库中选择、更新、插入和删除记录  。


图 9 Orders DataSet

  类型化的 DataSet 还允许您创建自定义的方法,以便检索和修改数据  。在 Orders DataSet(如图 9 所示)中,我基于 prGet_Orders 存储过程创建了一个类型化的 DataSet  。然后,通过数据组件查询配置向导,我向 OrdersTableAdapter 中添加了两个自定义方法:GetData 和 UpdateData  。这些方法是在与类型化 DataSet 的 XSD 相关联的类文件内部定义的;在该示例中,我的文件名为 OrdersDataSet.Designer.cs  。如果您想了解详细信息,可以打开这个自动生成的文件(但是您不应当修改它,因为如果该文件被重新生成,则您的更改将被改写)并查看自定义的 GetData 和 Update 方法以及为类型化 DataSet 创建的所有标准代码  。如果您运行示例页 Orders2.aspx,则它会直接绑定到上述自定义方法  。这可以显著减少您为中间层手动编写的代码数量  。

其他数据源控件细节

  现在我们已经完成了讨论,如果您知道数据源控件还可以通过一系列属性来公开缓存功能,则可能会很感兴趣  。通过将 EnableCaching 设置为 true 并将 CacheDuration 设置为很多秒,数据将在缓存中存储相应的时间  。还可以将 CacheExpirationPolicy 属性设置为 Absolute 或 Sliding  。Absolute 是默认值,它告诉缓存在加载后立即开始倒计时直至过期  。Sliding 策略告诉缓存在缓存数据每次被访问时重置过期倒计时  。在您要加载的数据不是非常容易改变的情况下,缓存技术可以帮助优化应用程序  。例如,在加载省、市甚至产品类别的 DropDownList 的数据源控件中使用缓存是有好处的,因为这些数据不会频繁更改  。

  ObjectDataSource 控件包装了挂钩到业务对象以调用业务方法的代码  。它还与数据绑定控件(例如,GridView)协同工作,以执行分页、排序以及在 ASP.NET 1.x 中必须手动编码的数据更改  。

小结

  ASP.NET 2.0 中的改进(尤其是在数据源和数据绑定控件领域中的改进)显著减少了产生带有完整分页、排序和编辑功能并填充了数据的网格所需的代码数量  。尽管数据源控件消除了过去必须手动编写的大量代码,但您仍然可以编写代码以便与数据源控件进行交互  。您不仅可以只通过指指点点来创建数据驱动的 Web 页,而且还可以编写代码来使用数据源控件的事件,例如,Selected、Selecting、Updated 或 Updating 事件  。

  转到原英文页面