基于数据内容的 ASP.NET 字母分页





4.00/5 (13投票s)
2004 年 4 月 6 日
3分钟阅读

72195

844
通过从现有数据派生的字母列表选择字母,在 DataGrid 中分页显示表格数据。

引言
显示姓名等数据记录时,按字母分组通常是一个不错的选择。我一直在我的门户网站的“用户”模块中使用字母分页,该模块是 IBuySpy 门户网站的一个高度修改版本。Code Project 的一篇 文章演示了这种方法,但该文章中的分页实现仍有改进空间。首先,最好从现有数据记录派生字母列表,而不是 A 到 Z,因为表中可能根本没有某些使用频率较低的字母的记录,并且作为额外的好处,这种从表格数据派生的字母列表还可以包含记录计数信息,以便在从表格中提取数据之前将其显示为工具提示。其次,为了提高效率,数据筛选应在 SQL Server 内部完成,并且只提取要显示的数据行,这对于繁忙网站上的大型数据表尤其重要。
这里实现的分页与我的门户网站的“用户”模块基本相同,并且与该模块一样,我也使用 ASP.NET 用户控件和三层 Web 模型。要运行它,您需要拥有 Visual Studio .NET、SQL Server 或 MSDE。数据来自 Northwind 数据库的 Customers 表。此 VS.NET 解决方案是用 VS.NET 1.0 构建的,因此它也可以与 1.1 一起使用。
使用代码
SQL Server 连接信息在 web.config 文件中设置,如下所示:
"server=localhost;Trusted_Connection=true;database=Northwind"
Trusted_Connection 需要 ASPNET 帐户被授予访问 Northwind 数据库的权限。要从数据表中获取字母列表,需要一些 SQL 代码,以下是从 Customers 表获取姓名首字母的存储过程:
CREATE PROCEDURE GetCustomerLNameInitials
AS
SELECT UPPER(SUBSTRING(CompanyName, 1, 1)) lni, COUNT(*) Num
FROM Customers 
GROUP BY UPPER(SUBSTRING(CompanyName, 1, 1))
ORDER BY lni
此存储过程不仅获取了首字母列表,还返回了每个字母的记录数,以便在字母选择列表的工具提示中显示。此字母列表是 Repeater 控件的数据源。(All) 按钮只是一个单独的 LinkButton,不属于 Repeater 控件。当选择一个字母时,使用另一个存储过程从数据库中提取该字母开头的相应数据行。
CREATE PROCEDURE GetCustomersByLNameInitial
(
   @Lni nchar(1)
)
AS
SELECT CompanyName, Address, City, Country
FROM Customers 
WHERE CompanyName LIKE @Lni + '%'
ORDER BY CompanyName
数据驱动应用程序的正确设计应始终尽量减少对数据库服务器的影响,当需要获取数据时,只获取所需的数据,不多也不少。
另一个存储过程用于获取 (All) 按钮的所有数据行。
所有存储过程都封装在一个数据访问类中,所有数据读取方法都返回 SqlDataReader,这是从数据库获取数据并将其绑定到 Web 控件的最有效方式。由于 Web 应用程序是无状态的,因此在用户请求之外无法保留任何数据,除非有一些严重的副作用,所以创建 DataTable 或 DataSet,仅在页面渲染时立即丢弃,是没有意义的。DataTable 和 DataSet 通常是 WinForm 应用程序或需要操作/传输数据时的良好选择。数据访问类中的数据访问方法如下所示:
    public SqlDataReader GetCustomersByLNameInitial(string Lni) 
    {
        SqlDataReader dr = null;
        // Create Instance of Connection and Command Object
        SqlConnection myConnection = new 
          SqlConnection(ConfigurationSettings.AppSettings["connectionString"]);
        SqlCommand myCommand = new 
          SqlCommand("GetCustomersByLNameInitial", myConnection);
            
        try 
        {
            // Mark the Command as a SPROC
            myCommand.CommandType = CommandType.StoredProcedure;
               
            // Add Parameters to SPROC
            SqlParameter parameterLni = 
               new SqlParameter("@Lni", SqlDbType.NChar, 1);
            parameterLni.Value = Lni;
            myCommand.Parameters.Add(parameterLni);                
            // Open the database connection and execute the command
            myConnection.Open();
            dr = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
            // clear Paramters
            myCommand.Parameters.Clear();
        }
        catch 
        {
            myConnection.Close();
            //throw;
        }
        return dr;
    }
没什么特别的!现在来看用户控件。其中包含 Repeater 控件。
<asp:Repeater id=LetterList Visible="true" runat="server">
  <ITEMTEMPLATE>
    <asp:linkbutton id=lniLetter runat="server" 
        ToolTip='<%# "Subtotal: " + DataBinder.Eval(Container.DataItem, "Num") %>' 
        commandargument='<%# DataBinder.Eval(Container.DataItem, "Lni")%>'>
      <%# DataBinder.Eval(Container.DataItem, "Lni")%>
    </asp:linkbutton>
  </ITEMTEMPLATE>
</asp:Repeater>
在这个用户控件的视觉部分,其他都是琐碎的。以下是此用户控件代码隐藏的一部分:
    private void Page_Load(object sender, System.EventArgs e)
    {
        if (!Page.IsPostBack) 
        {
            IniBindData();
        }
    }
    private void ShowAllUsers_Click(object sender, System.EventArgs e)
    {
        DataAccess da = new DataAccess();
        DataGrid1.DataSource = da.GetAllCutomers();
        DataGrid1.DataBind();        
    }
    private void LetterList_Select(object source, 
       System.Web.UI.WebControls.RepeaterCommandEventArgs e)
    {
        DataAccess da = new DataAccess();
        // find the selected letter
        string letter = (string)e.CommandArgument;
        // show the name list with this initial 
        DataGrid1.DataSource = da.GetCustomersByLNameInitial(letter);
        DataGrid1.DataBind();
    }
    //    Called once at page first load
    void IniBindData()
    {
        DataAccess da = new DataAccess();
        LetterList.DataSource = da.GetCustomerLNameInitials();
        LetterList.DataBind();
            
        int n = LetterList.Items.Count;
        if (n > 0)
        {
            // try to find the first letter on the list
            string letter = ((LinkButton)
               (LetterList.Items[0].Controls[1])).CommandArgument;
                // show the Names with the first letter
            DataGrid1.DataSource = da.GetCustomersByLNameInitial(letter);
            DataGrid1.DataBind();
        }
    }
大部分代码都易于理解。当此用户控件首次加载时,它会调用 IniBindData(),该函数获取字母列表,并将其绑定到 Repeater 控件以形成 LinkButton 行。如果列表不为空,此方法还将使用第一个字母的数据行加载 DataGrid。当 Repeater 字母列表上的 LinkButton 被点击时,会调用其事件处理程序 LetterList_Select,该处理程序会找出哪个字母被选中,然后用该字母下的行加载 DataGrid。与实际应用程序不同,用户控件代码没有异常检查。
历史
- 2004 年 4 月 6 日,初稿。
