ASP.NET - ObjectDataSource Web 服务器控件概述

来源:互联网 发布:直播截屏软件 编辑:程序博客网 时间:2024/06/05 00:27

 

      ASP.NET ObjectDataSource 控件表示具有数据检索和更新功能的中间层对象。ObjectDataSource 控件可用作数据绑定控件(如 GridViewFormView DetailsView 控件)的数据接口。可以使用这些控件在 ASP.NET 网页上显示和编辑中间层业务对象中的数据。

 

一、背景

大多数 ASP.NET 数据源控件,如 SqlDataSource,都在两层应用程序层次结构中使用。在该层次结构中,表示层(ASP.NET 网页)可以与数据层(数据库和 XML 文件等)直接进行通信。但是,常用的应用程序设计原则是,将表示层与业务逻辑相分离,而将业务逻辑封装在业务对象中。这些业务对象在表示层和数据层之间形成一层,从而生成一种三层应用程序结构。ObjectDataSource 控件通过提供一种将相关页上的数据控件绑定到中间层业务对象的方法,为三层结构提供支持。在不使用扩展代码的情况下,ObjectDataSource 使用中间层业务对象以声明方式对数据执行选择、插入、更新、删除、分页、排序、缓存和筛选操作。

ObjectDataSource 控件使用反射调用业务对象的方法,以对数据执行选择、更新、插入和删除操作。设置 ObjectDataSource 控件的 TypeName 属性来指定要用作源对象的类名称。

 

1.1、排序和分页

通过将请求中的排序和分页信息从 GridView 控件等数据绑定控件传递到要处理的数据对象,ObjectDataSource 控件可以对其他的排序和分页功能提供支持。此后,源数据对象或数据源控件本身可以对数据进行排序,并将数据返回到各页中。

 

1.2、缓存

ObjectDataSource 控件可以缓存基础业务对象返回的对象。但是,如果对象存放资源或保持不能在多个请求之间共享的状态,则不能缓存该对象,例如,打开的 DataReader 对象就是这样的对象。

 

1.3、筛选

如果由源数据对象返回到 ObjectDataSource 控件的对象是 DataSet DataTable 对象,则 ObjectDataSource 控件会支持使用 DataColumn 类的 Expression 属性的语法对筛选提供支持。通过筛选,无需使用新的选择条件对数据源进行重新查询,即可只公开与特殊的搜索条件匹配的行。

 

1.4、冲突检测

通过将 ObjectDataSource 控件的 ConflictDetection 属性设置为 true,可以指定 ObjectDataSource 控件应该包括调用源数据对象的更新方法时的原始值。此后,这些原始值可以包括在开放式并发检查中。

 

二、ObjectDataSource

      ObjectDataSource ASP.NET 数据源控件,用于向数据绑定控件表示数据识别中间层对象或数据接口对象。 可以结合使用 ObjectDataSource 控件与数据绑定控件,这样,只用少量代码或不用代码就可以在网页上显示、编辑和排序数据。

一种极为常见的应用程序设计做法是,将表示层与业务逻辑分开,将业务逻辑封装到业务对象中。 这些业务对象在表示层和数据层之间构成一个独特的层,从而得到一个三层应用程序结构。 ObjectDataSource 控件使开发人员能够在保留他们的三层应用程序结构的同时,使用 ASP.NET 数据源控件。

ObjectDataSource 控件使用反射创建业务对象的实例,并调用这些实例的方法以检索、更新、插入和删除数据。 TypeName 属性标识 ObjectDataSource 使用的类的名称。 ObjectDataSource 控件在每次调用方法时都创建并销毁类的实例,它在 Web 请求的生存期内不在内存中保留对象。 如果您使用的业务对象需要很多资源或者在其他方面需要很大开销来创建和销毁,您就需要认真考虑。 使用高开销对象可能并不是最佳设计选择,但是可以使用 ObjectCreatingObjectCreated ObjectDisposing 事件控制该对象的生命周期。

      说明: SelectMethodUpdateMethodInsertMethod DeleteMethod 属性标识的方法可以是实例方法或 static(在 Visual Basic 中为 Shared)方法。 如果方法为 static(在 Visual Basic 中为 Shared),则不创建业务对象的实例,也不引发 ObjectCreatingObjectCreated ObjectDisposing 事件。

      若要从业务对象中检索数据,请用检索数据的方法的名称设置 SelectMethod 属性。 如果此方法未返回 IEnumerable DataSet 对象,则运行时在 IEnumerable 集合中包装该对象。 如果方法签名带参数,可以将 Parameter 对象添加到 SelectParameters 集合中,然后将它们绑定到要传递给由 SelectMethod 属性指定的方法的值。 为使 ObjectDataSource 能够使用参数,这些参数必须与方法签名中的参数名称和类型相匹配。

每次调用 Select 方法时,ObjectDataSource 控件都检索数据。 此方法提供对 SelectMethod 属性所指定的方法的编程访问。 当调用绑定到 ObjectDataSource 的控件的 DataBind 方法时,这些控件自动调用 SelectMethod 属性指定的方法。 如果设置数据绑定控件的 DataSourceID 属性,该控件根据需要自动绑定到数据源中的数据。 建议通过设置 DataSourceID 属性将 ObjectDataSource 控件绑定到数据绑定控件。 或者,可以设置 DataSource 属性,但之后必须显式调用数据绑定控件的 DataBind 方法。 可以随时以编程方式调用 Select 方法以检索数据。

      根据 ObjectDataSource 控件使用的业务对象的功能,可以执行诸如更新、插入和删除的数据操作。 若要执行这些数据操作,请为要执行的操作设置适当的方法名称和任何关联的参数。 例如,对于更新操作,将 UpdateMethod 属性设置为业务对象方法的名称,该方法执行更新并将所需的任何参数添加到 UpdateParameters 集合中。 如果 ObjectDataSource 控件与数据绑定控件相关联,则由数据绑定控件添加参数。 这种情况下,需要确保方法的参数名称与数据绑定控件中的字段名称相匹配。 调用 Update 方法时,由代码显式执行更新或由数据绑定控件自动执行更新。 Delete Insert 操作遵循相同的常规模式。 假定业务对象以逐个记录(而不是以批处理)的方式执行这些类型的数据操作。

如果数据是作为 DataSet DataTable 对象返回的,ObjectDataSource 控件可以筛选由 SelectMethod 属性检索的数据。 ObjectDataSource 控件允许缓存所有类型的数据,但您不应缓存保留了不能进行旨在为多个请求提供服务的共享的资源或状态的对象(例如,打开的 SqlDataReader 对象),因为在为多个请求提供服务时会使用对象的同一实例。 可以使用格式字符串语法将 FilterExpression 属性设置为筛选表达式,并将表达式中的值绑定到 FilterParameters 集合中指定的参数。

尽管 ObjectDataSource 不在多个请求之间保留业务对象的实例,但它可以缓存 SelectMethod 属性的结果。 缓存数据时,对 Select 方法的后续调用将返回缓存的数据,而不是创建业务对象并使用反射来调用该对象的 SelectMethod 使用缓存可以避免以占用 Web 服务器上的内存为代价,创建对象和调用其数据方法。 EnableCaching 属性设置为 true CacheDuration 属性设置为在丢弃缓存前缓存存储数据的秒数时,ObjectDataSource 将自动缓存数据。 也可以指定 CacheExpirationPolicy 属性和可选的 SqlCacheDependency 属性。

 

下表描述 ObjectDataSource 控件的功能。

功能

要求

选择

SelectMethod 属性设置为业务对象方法的名称,该方法不仅选择数据,还通过编程方式或使用数据绑定控件,在 SelectParameters 集合中包含所有必需的参数。

排序

SortParameterName 属性设置为带有排序条件的 SelectMethod 方法中的参数名称。

筛选

FilterExpression 属性设置为一个筛选表达式,并选择将任何参数添加到 FilterParameters 集合中,以在调用 Select 方法时筛选数据。 SelectMethod 属性指定的方法必须返回 DataSet DataTable

分页

如果 SelectMethod 方法包含要检索的最大记录数的参数和要检索的第一个记录的索引参数,则支持数据源分页。 必须分别在 MaximumRowsParameterName StartRowIndexParameterName 属性中设置那些参数的名称。 即使 ObjectDataSource 控件不支持直接在 SelectMethod 属性指定的方法中分页,数据绑定控件自己或许也能够执行分页。 要使数据绑定控件能够执行分页,SelectMethod 属性指定的方法必须返回一个实现 ICollection 接口的对象。

更新

UpdateMethod 属性设置为业务对象方法的名称,该方法更新数据并在 UpdateParameters 集合中包含所有必需的参数。

删除

DeleteMethod 属性设置为业务对象方法或函数的名称,该方法或函数删除数据并在 DeleteParameters 集合中包含所有必需的参数。

插入

InsertMethod 属性设置为业务对象方法或函数的名称,该方法或函数插入数据并在 InsertParameters 集合中包含所有必需的参数。

缓存

根据缓存数据的缓存行为,将 EnableCaching 属性设置为 true,并设置 CacheDuration CacheExpirationPolicy 属性。

      与所有数据源控件一样,ObjectDataSource 控件与数据源视图类关联。 ObjectDataSource 控件是页面开发人员用来使用数据的接口,而 ObjectDataSourceView 类是数据绑定控件使用的接口。 此外,ObjectDataSourceView 类描述数据源控件的功能并执行实际的工作。 ObjectDataSource 控件仅有一个关联的 ObjectDataSourceView,而且它始终命名为 DefaultView 虽然 ObjectDataSourceView 对象由 GetView 方法公开,但它的许多属性和方法都是直接由 ObjectDataSource 控件包装和公开的。 在后台,ObjectDataSourceView 对象执行所有数据操作,包括检索、插入、更新、删除、筛选和排序数据。

ObjectDataSource 控件可用于 LINQ to SQL 类。 为此,请将 TypeName 属性设置为数据上下文类的名称。 此外,可将 SelectMethodUpdateMethodInsertMethod DeleteMethod 方法设置为数据上下文类中执行相应操作的方法。 必须为 ObjectDisposing 事件创建一个事件处理程序,才能取消对数据上下文类的释放。 此步骤必不可少,因为 LINQ to SQL 支持延迟执行,而 ObjectDataSource 控件会尝试在执行 Select 操作后释放数据上下文。 有关如何创建 LINQ to SQL 类的更多信息,请参见如何:在 Web 应用程序中创建 LINQ to SQL 类。

ObjectDataSource 控件没有可视化呈现。 它是作为控件实现的,以便您可以以声明方式创建它,还可以选择让它参与状态管理。 因此,ObjectDataSource 不支持可视化功能,如 EnableTheming SkinID 属性。

 

示例

本节包含两个代码示例。 第一个代码示例演示 GridView 控件如何使用 ObjectDataSource 对象在 ASP.NET 网页上显示数据。 第二个代码示例提供由此代码示例和许多其他 ObjectDataSource 代码示例使用的中间层业务对象的示例。

 

2.1、下面的代码示例演示 GridView 控件如何使用 ObjectDataSource 控件在 Web 窗体页上显示数据。 ObjectDataSource 用它的 TypeName 属性标识业务对象的部分或完全限定类名,用它的 SelectMethod 属性标识为检索数据而调用的业务对象方法。 在运行时创建该对象,并使用反射功能调用该方法。 GridView 控件通过 SelectMethod 属性返回的 IEnumerable 集合枚举数据,并显示数据。

<%@ Register TagPrefix="aspSample" Namespace="Samples.AspNet.CS" Assembly="Samples.AspNet.CS" %>

<%@ Page language="c#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html  >

  <head>

    <title>ObjectDataSource - C# Example</title>

  </head>

  <body>

    <form id="Form1" method="post" runat="server">

 

        <asp:gridview

          id="GridView1"

          runat="server"

          datasourceid="ObjectDataSource1" />

 

        <asp:objectdatasource

          id="ObjectDataSource1"

          runat="server"

          selectmethod="GetAllEmployees"

          typename="Samples.AspNet.CS.EmployeeLogic" />

 

    </form>

  </body>

</html>

 

      2.2、下面的代码示例提供由此示例和许多其他 ObjectDataSource 代码示例使用的中间层业务对象的示例。 此代码示例由以下两个基类组成:

·EmployeeLogic 类,这是封装业务逻辑的无状态类。

·NorthwindEmployee 类,这是仅包含从数据层加载和保留数据所需的基本功能的模型类。

提供附加 NorthwindDataException 类只是为了便于使用。

这组示例类与 Northwind Traders 数据库一起使用,该数据库是 Microsoft SQL Server Microsoft Access 自带的数据库。 要获得完整的可运行示例,您必须结合所提供的 Web 窗体代码示例来编译和使用这些类。

此示例的设计简单、易用,它演示了业务对象与 ObjectDataSource 控件之间最常见的交互方式之一。 它不是设计建议。 在一些示例中,将其他方法添加到了 EmployeeLogic NorthwindEmployee 类,或对这组类进行了修改以演示基本概念。

namespace Samples.AspNet.CS {

 

using System;

using System.Collections;

using System.Collections.Specialized;

using System.Configuration;

using System.Data;

using System.Data.SqlClient;

using System.Web.UI;

using System.Web.UI.WebControls;

  //

  // EmployeeLogic is a stateless business object that encapsulates

  // the operations one can perform on a NorthwindEmployee object.

  //

  public class EmployeeLogic {

 

    // Returns a collection of NorthwindEmployee objects.

    public static ICollection GetAllEmployees () {

      ArrayList al = new ArrayList();

 

      ConnectionStringSettings cts = ConfigurationManager.ConnectionStrings["NorthwindConnection"];

 

      SqlDataSource sds

        = new SqlDataSource(cts.ConnectionString, "SELECT EmployeeID FROM Employees");

 

      try {

 

        IEnumerable IDs = sds.Select(DataSourceSelectArguments.Empty);

 

        // Iterate through the Enumeration and create a

        // NorthwindEmployee object for each ID.

        foreach (DataRowView row in IDs) {

          string id = row["EmployeeID"].ToString();

          NorthwindEmployee nwe = new NorthwindEmployee(id);

          // Add the NorthwindEmployee object to the collection.

          al.Add(nwe);

        }

      }

      finally {

        // If anything strange happens, clean up.

        sds.Dispose();

      }

 

      return al;

    }

    public static NorthwindEmployee GetEmployee(object anID) {

      return new NorthwindEmployee(anID);

    }

 

    public static void UpdateEmployeeInfo(NorthwindEmployee ne) {

      bool retval = ne.Save();

      if (! retval) { throw new NorthwindDataException("UpdateEmployee failed."); }

    }

 

    public static void DeleteEmployee(NorthwindEmployee ne) { }

 

  }

 

  public class NorthwindEmployee {

 

    public NorthwindEmployee () {

      ID = DBNull.Value;

      lastName = "";

      firstName = "";

      title="";

      titleOfCourtesy = "";

      reportsTo = -1;

    }

 

    public NorthwindEmployee (object anID) {

      this.ID = anID;

 

      ConnectionStringSettings cts = ConfigurationManager.ConnectionStrings["NorthwindConnection"];

 

        SqlConnection conn = new SqlConnection (cts.ConnectionString);

      SqlCommand sc =

        new SqlCommand(" SELECT FirstName,LastName,Title,TitleOfCourtesy,ReportsTo " +

                       " FROM Employees " +

                       " WHERE EmployeeID = @empId",

                       conn);

      // Add the employee ID parameter and set its value.

      sc.Parameters.Add(new SqlParameter("@empId",SqlDbType.Int)).Value = Int32.Parse(anID.ToString());

      SqlDataReader sdr = null;

 

      try {

        conn.Open();

        sdr = sc.ExecuteReader();

 

        // This is not a while loop. It only loops once.

        if (sdr != null && sdr.Read()) {

          // The IEnumerable contains DataRowView objects.

          this.firstName        = sdr["FirstName"].ToString();

          this.lastName         = sdr["LastName"].ToString();

          this.title            = sdr["Title"].ToString();

          this.titleOfCourtesy  = sdr["TitleOfCourtesy"].ToString();

          if (! sdr.IsDBNull(4)) {

            this.reportsTo        = sdr.GetInt32(4);

          }

        }

        else {

          throw new NorthwindDataException("Data not loaded for employee id.");

        }

      }

      finally {

        try {

          if (sdr != null) sdr.Close();

          conn.Close();

        }

        catch (SqlException) {

          // Log an event in the Application Event Log.

          throw;

        }

      }

    }

 

    private object ID;

 

    private string lastName;

    public string LastName {

      get { return lastName; }

      set { lastName = value; }

    }

 

    private string firstName;

    public string FirstName {

      get { return firstName; }

      set { firstName = value;  }

    }

 

    private string title;

    public String Title {

      get { return title; }

      set { title = value; }

    }

 

    private string titleOfCourtesy;

    public string Courtesy {

      get { return titleOfCourtesy; }

      set { titleOfCourtesy = value; }

    }

 

    private int    reportsTo;

    public int Supervisor {

      get { return reportsTo; }

      set { reportsTo = value; }

    }

 

    public bool Save () {

      return true;

    }

  }

 

  internal class NorthwindDataException: Exception {

    public NorthwindDataException(string msg) : base (msg) { }

  }

}

 

 

原创粉丝点击