使用数据源控件对数据进行排序

更新:2007 年 11 月

通过使用数据源控件和数据绑定控件,可以在 ASP.NET 网页中显示数据。有些数据控件还允许用户对数据进行排序,而不用编写任何代码。

如果要使用户能够在运行时对数据排序,可以使用 LinqDataSourceObjectDataSourceSqlDataSourceAccessDataSource 控件作为数据源控件。若要显示可由用户排序的数据,可以使用 GridView 控件或 ListView 控件。

提供用于排序的用户界面

您可以创建任何用于排序的用户界面 (UI)。但是,GridViewListView 控件提供了默认的用户界面排序。

GridView 控件支持在不需要任何编程的情况下通过单个列排序。通过将 AllowSorting 属性设置为 true,可自动将每个列的标题文本创建为向数据源控件传递排序表达式的链接按钮。而通过处理排序事件,还可以进一步自定义 GridView 控件的排序功能。有关更多信息,请参见对 GridView Web 服务器控件中的数据进行排序

通过在 ListView 控件的 LayoutTemplate 模板中添加一个按钮,并将该按钮的 CommandName 属性设置为“Sort”,可以对该控件中显示的数据排序。该按钮的 CommandArgument 属性应设置为要用作排序依据的列名。单击“Sort”(排序)按钮可在排序方向 AscendingDescending 之间切换。有关更多信息,请参见 ListView Web 服务器控件概述演练:使用 ListView Web 服务器控件对数据进行显示、分页和排序

在数据源控件中启用排序

对排序提供内置支持的数据源控件是 LinqDataSourceObjectDataSourceSqlDataSourceAccessDataSource 控件。在将 AutoSort 属性设置为 true(默认值)时,LinqDataSource 控件会支持排序,如下面的示例所示:

<asp:LinqDataSource 
    ContextTypeName="ExampleDataContext" 
    TableName="Products" 
    AutoPage="true"
    AutoSort="true"
    ID="LinqDataSource1" 
    runat="server">
</asp:LinqDataSource>
<asp:GridView 
    AllowPaging="true"
    AllowSorting="true"
    DataSourceID="LinqDataSource1"
    ID="GridView1" 
    runat="server">
</asp:GridView>
<asp:LinqDataSource 
    ContextTypeName="ExampleDataContext" 
    TableName="Products" 
    AutoPage="true"
    AutoSort="true"
    ID="LinqDataSource1" 
    runat="server">
</asp:LinqDataSource>
<asp:GridView 
    AllowPaging="true"
    AllowSorting="true"
    DataSourceID="LinqDataSource1"
    ID="GridView1" 
    runat="server">
</asp:GridView>

SqlDataSourceAccessDataSource 控件只有在其 DataSourceMode 属性设置为 DataSet(默认)时才支持排序,如下面的示例所示:

<asp:GridView ID="EmployeesGridView" 
  DataSourceID="EmployeesSqlDataSource" 
  DataKeyNames="EmployeeID" 
  AllowSorting="True"
  RunAt="Server" />

<asp:SqlDataSource ID="EmployeesSqlDataSource"  
  SelectCommand="SELECT EmployeeID, LastName, FirstName FROM Employees" 
  Connectionstring="<%$ ConnectionStrings:NorthwindConnectionString %>" 
  RunAt="server" />
<asp:GridView ID="EmployeesGridView" 
  DataSourceID="EmployeesSqlDataSource" 
  DataKeyNames="EmployeeID" 
  AllowSorting="True"
  RunAt="Server" />

<asp:SqlDataSource ID="EmployeesSqlDataSource"  
  SelectCommand="SELECT EmployeeID, LastName, FirstName FROM Employees" 
  Connectionstring="<%$ ConnectionStrings:NorthwindConnectionString %>" 
  RunAt="server" />

如果 SelectMethod 返回的对象是 DataSetDataTableDataView 对象,则 ObjectDataSource 控件支持排序。ObjectDataSource 还支持按排序后的顺序对数据源中的结果进行检索。

自定义排序

您可以自定义数据绑定控件和数据源控件执行排序的方式。这样,将可以修改自动排序的执行方式,也可以创建自定义排序例程。

使用 LinqDataSource 控件时,可通过将 AutoSort 属性设置为 false 自定义排序。随后可以为 Selecting 事件创建处理程序。

使用 ObjectDataSourceSqlDataSource 控件时,可通过 SortParameterName 属性来利用各种排序功能。可以将 SortParameterName 属性设置为包含传递到数据源控件的排序表达式的参数名称。排序表达式是作为排序依据的字段的列表,这些字段间以逗号分隔(还可以选择 DESC 标识符按降序排列)。有关排序表达式格式的详细信息,请参见 DataView.Sort 属性。

SortParameterName 属性标识的参数被传递给 ObjectDataSource 控件的 SelectMethod 或作为参数集合的一部分传递给 SqlDataSource 控件的 SelectCommandObjectDataSource 控件可以使用在排序参数中传递给它的信息,从而按排序后的顺序返回数据。对于 SqlDataSource 控件,由于不能将参数作为 ORDER BY 子句的一部分进行传递,因此必须提供可获取排序参数并返回已排序数据的存储过程的名称。

下面的代码示例演示一个 ObjectDataSource 控件声明,它将一个名为 sortColumns 的参数标识为排序参数名称:

<asp:ObjectDataSource 
  ID="EmployeesObjectDataSource" 
  runat="server" 
  TypeName="Samples.AspNet.Controls.NorthwindEmployee" 
  SortParameterName="SortColumns"
  EnablePaging="true"
  StartRowIndexParameterName="StartRecord"
  MaximumRowsParameterName="MaxRecords" 
  SelectMethod="GetAllEmployees" >
</asp:ObjectDataSource>
<asp:ObjectDataSource 
  ID="EmployeesObjectDataSource" 
  runat="server" 
  TypeName="Samples.AspNet.Controls.NorthwindEmployee" 
  SortParameterName="SortColumns"
  EnablePaging="true"
  StartRowIndexParameterName="StartRecord"
  MaximumRowsParameterName="MaxRecords" 
  SelectMethod="GetAllEmployees" >
</asp:ObjectDataSource>

下面的代码示例演示 ObjectDataSource 控件源对象中的一个方法。该方法被标识为 SelectMethod。由 SortParameterName 属性标识的参数用于对从数据库中检索的数据进行排序。

Public Shared Sub Initialize()    
  ' Initialize data source. Use "Northwind" connection string from configuration.

  If ConfigurationManager.ConnectionStrings("Northwind") Is Nothing OrElse _
     ConfigurationManager.ConnectionStrings("Northwind").ConnectionString.Trim() = "" Then      
    Throw New Exception("A connection string named 'Northwind' with a valid connection string " & _
                        "must exist in the <connectionStrings> configuration section for the application.")
  End If

  _connectionString = _
    ConfigurationManager.ConnectionStrings("Northwind").ConnectionString

  _initialized = True
End Sub



' Select all employees.

<DataObjectMethod(DataObjectMethodType.Select, True)> _
Public Shared Function GetAllEmployees(sortColumns As String, startRecord As Integer, maxRecords As Integer) As DataTable

  VerifySortColumns(sortColumns)

  If Not _initialized Then Initialize()

  Dim sqlCommand As String = "SELECT EmployeeID, LastName, FirstName, Address, City, Region, PostalCode FROM Employees "

  If sortColumns.Trim() = "" Then
    sqlCommand &= "ORDER BY EmployeeID"
  Else
    sqlCommand &= "ORDER BY " & sortColumns
  End If

  Dim conn As SqlConnection  = New SqlConnection(_connectionString)
  Dim da   As SqlDataAdapter = New SqlDataAdapter(sqlCommand, conn) 

  Dim ds As DataSet =  New DataSet() 

  Try
    conn.Open()
    da.Fill(ds, startRecord, maxRecords, "Employees")
  Catch e As SqlException
    ' Handle exception.
  Finally      
    conn.Close()
  End Try

  If ds.Tables("Employees") IsNot Nothing Then _
    Return ds.Tables("Employees")

  Return Nothing
End Function


'''''
' Verify that only valid columns are specified in the sort expression to aSub a SQL Injection attack.

Private Shared Sub VerifySortColumns(sortColumns As String)

  If sortColumns.ToLowerInvariant().EndsWith(" desc") Then _
    sortColumns = sortColumns.Substring(0, sortColumns.Length - 5)

  Dim columnNames() As String = sortColumns.Split(",")

  For Each columnName As String In columnNames      
    Select Case columnName.Trim().ToLowerInvariant()        
      Case "employeeid"
      Case "lastname"
      Case "firstname"
      Case ""
      Case Else
        Throw New ArgumentException("SortColumns contains an invalid column name.")
    End Select
  Next
End Sub
public static void Initialize()
{
  // Initialize data source. Use "Northwind" connection string from configuration.

  if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
      ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "")
  {
    throw new Exception("A connection string named 'Northwind' with a valid connection string " + 
                        "must exist in the <connectionStrings> configuration section for the application.");
  }

  _connectionString = 
    ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

  _initialized = true;
}


// Select all employees.

[DataObjectMethod(DataObjectMethodType.Select, true)]
public static DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords)
{
  VerifySortColumns(sortColumns);

  if (!_initialized) { Initialize(); }

  string sqlCommand = "SELECT EmployeeID, LastName, FirstName, Address, City, Region, PostalCode FROM Employees ";

  if (sortColumns.Trim() == "")
    sqlCommand += "ORDER BY EmployeeID";
  else
    sqlCommand += "ORDER BY " + sortColumns;

  SqlConnection conn = new SqlConnection(_connectionString);
  SqlDataAdapter da  = new SqlDataAdapter(sqlCommand, conn); 

  DataSet ds =  new DataSet(); 

  try
  {
    conn.Open();
    da.Fill(ds, startRecord, maxRecords, "Employees");
  }
  catch (SqlException e)
  {
    // Handle exception.
  }
  finally
  {
    conn.Close();
  }

  if (ds.Tables["Employees"] != null)
    return ds.Tables["Employees"];

  return null;
}


//////////
// Verify that only valid columns are specified in the sort expression to avoid a SQL Injection attack.

private static void VerifySortColumns(string sortColumns)
{
  if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
    sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);

  string[] columnNames = sortColumns.Split(',');

  foreach (string columnName in columnNames)
  {
    switch (columnName.Trim().ToLowerInvariant())
    {
      case "employeeid":
        break;
      case "lastname":
        break;
      case "firstname":
        break;
      case "":
        break;
      default:
        throw new ArgumentException("SortColumns contains an invalid column name.");
        break;
    }
  }
}

有关更多信息,请参见创建 ObjectDataSource 控件源对象

请参见

其他资源

数据源 Web 服务器控件