datagrid自定义分页+高效存储过程

来源:互联网 发布:jquery map转json 编辑:程序博客网 时间:2024/05/22 09:49
 datagrid自定义分页是datagrid的一个重要的功能,datagrid自定义分页主要用于数据源较大时。因为数据源大(记录多),加载时间长,反应慢,耗服务器的资源。而且每显示一页就要重新加载所有的数据。而如果我们用自定义分页,则每一次只加载一页的记录,也就是只加载我们要显示的记录。这样加载数据时间短,反应快,节约服务器的资源。在做项目的过程中,我们也经常需要用到自定义功能。今天我们就说说怎样自定义分页。
     先看看datagrid的自定义分页的原理,它主要依据两个主要属性,第一个就是VirtualItemCount属性,它表示datagrid一共要显示多少条记录,它就是的作用是用于生成pager(分页导航行),通过结合另外两个属性pagesize和PageButtonCount,datagrid就知道要分成多少页了及当前要显示多少个分页按钮,我们不难得到总共要显示的总页数=(VirtualItemCount+pagesize-1)/pagesize;如要总页数<PageButtonCount,则显示总页数个按钮;如果总页数>PageButtonCount,则显示PageButtonCount个按钮,当然到了最后一页就只显示VirtualItemCount% pagesize(总记录条数除以每页显示记录的余数)个按钮。另一个重要的属性就是datasource(数据源),自定义分页的一个重要的特点是显示数据源中所有的记录,如果数据源中有一条记录,则显示一条记录;如果数据源中有一万条记录,则它会显示一万条记录,可能你的机子就慢了 : )。所以自定义最重要的一点是如何设置或获取数据源了。
     接下来,我们先说说自定义分页的主要步骤:
1.     设置datagrid的VirtualItemCount属性;
2.     获取datagrid的datasource(数据源);
3.     绑定数据到datagrid;
4.     设置新页的页码(datagrid.currentpageindex属性)。
重复上述2,3,4步。
下面我们以一个例子来讲解datagrid 的自定义过程。
例子要求机子装有ms sql server 7.0 或 2000,当然还要能运行asp.net页了(废话)。
我们先来写一个通用的存储过程,用于分页,返回某页的要显示的记录集,及一个输出参数--总的记录条数,但这个存储过程有缺陷,例如只能用于单表查询,必须要有条件语句等。
CREATE PROCEDURE up_custompage @vc_order_column_name varchar(100),@vc_select_column_list varchar(100),
@vc_select_table_list varchar(100),@vc_condition varchar(100),@page_size int,@current_page int,@total1 int output
/*
     (
         @vc_order_column_name :表要排序列的列名,只能按一列排序,而且该列必须得在输出列表中;
         @vc_select_column_list :返回列的列名列表;
         @vc_select_table_list:要查询的表名;
         @vc_condition:查询条件的字符串,必须要有查询条列,否则会抛出异常;
         @page_size:每页显示记录的条数;
         @current_page:当前页的页码;
         @total1:所有符合条件的记录的总数。
         构造的sql语句=select top 每页显示记录的条数 * from (select top 每页显示记录的条数 返回列的列名列表 from 要查询的表名 where 要排序列的列名 in (select top 每页显示记录的条数 X 当前页的页码   要排序列的列名   from 要查询的表名 where 查询条件 order by 要排序列的列名) order by 要排序列的列名 desc ) as temp1 order by 要排序列的列名
     )
*/
AS
--声明要用到的变量,@temp1是正常的分页语句字符串,@temp2是最后一页的分页语句字符串,@page_total表一共有几页,@last_page
--是最后一页的页码
declare @temp1 varchar(500),@temp2 nvarchar(500),@page_total int,@last_page int
--构造获得总页的数的检索语句
set @temp2=N'select @total2=count(*) from ' + @vc_select_table_list + ' where ' + @vc_condition
--执行检索语句,取得总的记录条数
exec sp_executesql @temp2,N' @total2 int output ',@total1 output

/*构造分页检索语句,基本原理是先取出@page_size*@current_page条记录,相当于是取出当前页及当前页前面的所有页面的记录然后取出当前面所要显示的记录,也就是反序排序后取前@page_size条记录;最后再反序排序(因为前面的顺序被反排过一次,现在再反排一次,正好是我们要的顺序),最后执行,返回结果集。
*/
if @total1>0
begin
set @page_total=(@total1+@page_size-1)/@page_size
--如果当前页不是最后一页
if @current_page<@page_total
set @temp1='select top ' + cast(@page_size as varchar(4)) + ' * from
(select top ' + cast(@page_size as varchar(4))   + ' ' + @vc_select_column_list + ' from ' + @vc_select_table_list +' where ' + @vc_order_column_name
+ ' in (select top ' + cast(@page_size*@current_page as varchar(10)) + ' ' + @vc_order_column_name + ' from ' +
@vc_select_table_list + ' where '+ @vc_condition   + ' order by ' +
@vc_order_column_name + ') order by ' + @vc_order_column_name   + ' DESC) as temp1 order by ' + @vc_order_column_name
else
--最后一页只返回分页后的最后几条记录,也就是@total1%@page_size条记录
begin
set @last_page=@total1%@page_size
set @temp1='select top ' + cast(@last_page as varchar(4)) + ' * from
(select top ' + cast(@last_page as varchar(4))   + ' ' + @vc_select_column_list + ' from ' + @vc_select_table_list +' where ' + @vc_order_column_name
+ ' in (select top ' + cast(@total1 as varchar(10)) + ' ' + @vc_order_column_name + ' from ' +
@vc_select_table_list + ' where '+ @vc_condition   + ' order by ' +
@vc_order_column_name + ') order by ' + @vc_order_column_name   + ' DESC) as temp1 order by ' + @vc_order_column_name
end
--执行检索
exec(@temp1)
end
else
return

-------------------------------------------------------------------------

然后在新建一个aspx页面,代码如下:
<%@ Page language="c#" Codebehind="custompage.aspx.cs" AutoEventWireup="false" Inherits="cyc_test.custompage" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
     <HEAD>
         <title>custompage</title>
         <meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
         <meta content="C#" name="CODE_LANGUAGE">
         <meta content="JavaScript" name="vs_defaultClientScript">
         <meta content=""'>http://schemas.microsoft.com/intellisense/ie5& ... ot;vs_targetSchema">
         <style>A { BEHAVIOR: url(MouseOver.htc) }
     HR { COLOR: black; HEIGHT: 2px }
     .StdText { FONT-WEIGHT: bold; FONT-SIZE: 9pt; FONT-FAMILY: verdana }
     .StdTextBox { BORDER-RIGHT: black 1px solid; BORDER-TOP: black 1px solid; FONT-SIZE: 9pt; FILTER: progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true'); BORDER-LEFT: black 1px solid; BORDER-BOTTOM: black 1px solid; FONT-FAMILY: verdana }
     .Shadow { FILTER: progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true') }
         </style>
     </HEAD>
     <body style="FONT-FAMILY: arial" bgColor="ivory" MS_POSITIONING="GridLayout">
         <form id="custompage" method="post" runat="server">
             <h2>项目总结之datagrid自定义分页篇
             </h2>
             <asp:label id="Label1" runat="server" font-bold="true" cssclass="StdText">当前路径: </asp:label><asp:label id="lblURL" style="COLOR: blue" runat="server" cssclass="StdText"></asp:label>
             <!-- Query --><br>
             <asp:label id="Label2" runat="server" cssclass="stdtext" Text="查询语句:"></asp:label>
<asp:textbox id="Textbox1" runat="server" cssclass="stdtextbox" text="SELECT employeeid, firstname, lastname,title FROM Employees where employeeid>0 order by employeeid" width="765px" Enabled="false"></asp:textbox>
             <hr>
             <!-- Show the information -->
<asp:datagrid id="grid" runat="server" OnPageIndexChanged="PageIndexChanged" AllowCustomPaging="True" AllowPaging="True" PageSize="5" BorderWidth="1" BorderColor="black" BorderStyle="solid" BackColor="White" CssClass="Shadow" GridLines="vertical" CellSpacing="0" CellPadding="2" Font-Names="Verdana" Font-Size="Smaller">
                 <PagerStyle Font-Bold="true" Mode="NumericPages" BackColor="palegreen" />
                 <AlternatingItemStyle BackColor="#eeeeee" />
                 <ItemStyle BackColor="White" />
                 <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="Navy" />
             </asp:datagrid></form>
     </body>
</HTML>
再写后台的源代码:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;

namespace cyc_test
{
     /// <summary>
     /// custompage 的摘要说明。
     /// </summary>
     public class custompage : System.Web.UI.Page
     {
         protected System.Web.UI.WebControls.Label Label1;
         protected System.Web.UI.WebControls.Label lblURL;
         protected System.Web.UI.WebControls.Label Label2;
         protected System.Web.UI.WebControls.TextBox Textbox1;
         protected System.Web.UI.WebControls.DataGrid grid;
    
         private void Page_Load(object sender, System.EventArgs e)
         {
             // 第一次加载页时,初始化
             if (!Page.IsPostBack)
             {
                 lblURL.Text = Request.Url + "<hr>";    
                 createdatasource(1);
             }
         }

         //绑定datagrid的函数
protected void createdatasource(int current_page)
         {
             string str_table_name,str_column_list,str_order_column,str_condition;
             //查询的表名
             str_table_name="employees";
             //返回的列名列表
             str_column_list="employeeid,firstname,lastname,title";
             //排序列的列名
             str_order_column="employeeid";
             //查询的表件
             str_condition="employeeid>0";
             string strConn = "DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";
             SqlConnection conn = new SqlConnection(strConn);
             //声明执行存储过程的SqlCommand
             SqlCommand scd_sel=new SqlCommand("up_custompage",conn);
             scd_sel.CommandType=CommandType.StoredProcedure;
             //给存储过程的参数赋值
             SqlParameter sp_temp;
             sp_temp=scd_sel.Parameters.Add("@vc_order_column_name",SqlDbType.VarChar,100);
             sp_temp.Direction=ParameterDirection.Input;
             sp_temp.Value=str_order_column;
             sp_temp=scd_sel.Parameters.Add("@vc_select_column_list",SqlDbType.VarChar,100);
             sp_temp.Direction=ParameterDirection.Input;
             sp_temp.Value=str_column_list;
             sp_temp=scd_sel.Parameters.Add("@vc_select_table_list",SqlDbType.VarChar,100);
             sp_temp.Direction=ParameterDirection.Input;
             sp_temp.Value=str_table_name;
             sp_temp=scd_sel.Parameters.Add("@vc_condition",SqlDbType.VarChar,100);
             sp_temp.Direction=ParameterDirection.Input;
             sp_temp.Value=str_condition;
             sp_temp=scd_sel.Parameters.Add("@page_size",SqlDbType.Int);
             sp_temp.Direction=ParameterDirection.Input;
             sp_temp.Value=grid.PageSize;
             sp_temp=scd_sel.Parameters.Add("@current_page",SqlDbType.Int);
             sp_temp.Direction=ParameterDirection.Input;
             sp_temp.Value=current_page;
             sp_temp=scd_sel.Parameters.Add("@total1",SqlDbType.Int);
             sp_temp.Direction=ParameterDirection.Output;
            
             //执行存储过程
             SqlDataAdapter sda=new SqlDataAdapter();
             sda.SelectCommand=scd_sel;
             if (conn.State==ConnectionState.Closed)
                 conn.Open();
             DataSet ds=new DataSet();
             sda.Fill(ds,"tb1");        
             conn.Close();
             //设置VirtualItemCount属性
             grid.VirtualItemCount=(int)scd_sel.Parameters["@total1"].Value;
             //绑定数据源
             grid.DataSource=ds.Tables["tb1"].DefaultView;
             grid.DataBind();
         }

         #region Web Form Designer generated code
         override protected void OnInit(EventArgs e)
         {
             //
             // CODEGEN:该调用是 ASP.NET Web 窗体设计器所必需的。
             //
             InitializeComponent();
             base.OnInit(e);
         }
        
         /// <summary>
         /// 设计器支持所需的方法 - 不要使用代码编辑器修改
         /// 此方法的内容。
         /// </summary>
         private void InitializeComponent()
         {    
             this.grid.ItemCreated += new System.Web.UI.WebControls.DataGridItemEventHandler(this.grid_ItemCreated);
             this.grid.PageIndexChanged += new System.Web.UI.WebControls.DataGridPageChangedEventHandler(this.PageIndexChanged);
             this.Load += new System.EventHandler(this.Page_Load);

         }
         #endregion
         //datagrid的ItemCreated事件,用于定制分页导航行
         private void grid_ItemCreated(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
         {
            
             ListItemType elemType = e.Item.ItemType;
             //定制分页导航行,样式为[1] [2] 第 3 页 [4]
             if (elemType == ListItemType.Pager)
             {
                
                 TableCell pager = (TableCell) e.Item.Controls[0];
            
                 for (int i=0; i<pager.Controls.Count; i+=2)
                 {
                     Object o = pager.Controls[i];
                     if (o is LinkButton)
                     {
                         LinkButton h = (LinkButton) o;
                         h.Text = "[ " + h.Text + " ]";
                     }
                     else
                     {
                         Label l = (Label) o;
                         l.Text = "第" + l.Text + “页”;
                     }
                 }
             }
         }    
         //页选中(分页)事件
         public void PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
         {
             grid.CurrentPageIndex = e.NewPageIndex;
             //页码值是从零开始的,所以要加一
             createdatasource(grid.CurrentPageIndex+1);
         }
     }
}

    要运行上面的示例,请按上面的顺序先创建存储过程,再写页面的代码,最后是源代码。示例参考了《构建Web解决方案---应用ASP.NET和ADO.NET》中的分页思路。在本机调试通过。大家只要明白存储过程分页的思想就可以了。如果大家有更好的方案,请提出来,也许你的更好!
    这一段时间又开始了新的项目,所以这篇文章写得比较仓促,可能有些地方讲得不明白,大家可以提问和讨论。希望对大家有所帮助。
ALTER PROCEDURE up_custompage @vc_order_column_name varchar(100),@vc_select_column_list varchar(100),
@vc_select_table_list varchar(100),@vc_condition varchar(100),@page_size int,@current_page int,@total1 int output
/*
     (
         @vc_order_column_name :表要排序列的列名,只能按一列排序,而且该列必须得在输出列表中;
         @vc_select_column_list :返回列的列名列表,可以为多个列;
         @vc_select_table_list:要查询的表名及关联表的连接;
         @vc_condition:查询条件的字符串,必须要有查询条列,否则会抛出异常;
         @page_size:每页显示记录的条数;
         @current_page:当前页的页码;
         @total1:所有符合条件的记录的总数。
     )
*/
AS
--声明要用到的变量,@temp1是正常的分页语句字符串,@temp2是最后一页的分页语句字符串,@page_total表一共有几页,@last_page
--是最后一页的页码
declare @temp1 varchar(500),@temp2 nvarchar(500),@page_total int,@last_page int
--构造获得总页的数的检索语句
set @temp2=N'select @total2=count(*) from ' + @vc_select_table_list + ' where ' + @vc_condition
--执行检索语句,取得总的记录条数
exec sp_executesql @temp2,N' @total2 int output ',@total1 output

/*构造分页检索语句,基本原理是先取出@page_size*@current_page条记录,相当于是取出当前页及当前页前面的所有页面的记录
然后取出当前面所要显示的记录,也就是反序排序后取前@page_size条记录;最后再反序排序(因为前面的顺序被反排过一次,
现在再反排一次,正好是我们要的顺序),最后执行,返回结果集。
*/
if @total1>0
begin
set @page_total=(@total1+@page_size-1)/@page_size
--如果当前页不是最后一页
if @current_page<@page_total or @total1%@page_size=0
set @temp1='select top ' + cast(@page_size as varchar(4)) + ' * from
(select top ' + cast(@page_size as varchar(4))   + ' ' + @vc_select_column_list + ' from ' + @vc_select_table_list +' where ' + @vc_order_column_name
+ ' in (select top ' + cast(@page_size*@current_page as varchar(10)) + ' ' + @vc_order_column_name + ' from ' +
@vc_select_table_list + ' where '+ @vc_condition   + ' order by ' +
@vc_order_column_name + ') order by ' + @vc_order_column_name   + ' DESC) as temp1 order by ' + @vc_order_column_name
else
--最后一页只返回分页后的最后几条记录,也就是@total1%@page_size条记录
begin
set @last_page=@total1%@page_size
set @temp1='select top ' + cast(@last_page as varchar(4)) + ' * from
(select top ' + cast(@last_page as varchar(4))   + ' ' + @vc_select_column_list + ' from ' + @vc_select_table_list +' where ' + @vc_order_column_name
+ ' in (select top ' + cast(@total1 as varchar(10)) + ' ' + @vc_order_column_name + ' from ' +
@vc_select_table_list + ' where '+ @vc_condition   + ' order by ' +
@vc_order_column_name + ') order by ' + @vc_order_column_name   + ' DESC) as temp1 order by ' + @vc_order_column_name
end
--执行检索
exec(@temp1)
end
else
return
原创粉丝点击