20
2012
07

ASP.NET的最通用的分页方式

一说到“分页”,大家可能不会很陌生,如果做过ASP.NET的,基本都做过,接触过分页,更有甚者更是精通。如果精通的分页的人就不用看这文章了。其内容也是平平。只是给刚接触分页和不是很了解分页的查看一下。

通常分页分以下几种方式实现:

(1)一些数据绑定控件自带的分页控件(例如GridView)

(2)应用分页类PagedDataSource

(3)用开源分页AspNetPager。它的功能也比较强大。

(4)手动写前台Html和数据库的分页存储过程

。。。等等。前三种方式不灵活,性能也有相应问题,个人比较倾向于第四种方式,它是自己可以控制的。

我们在写分页时一定要考虑以下几个点。

(1)效率问题与速度问题,数据量比较大时,不能一次性把数据加载到内存,而是需要哪一页的数据时,自动去加载需要的那一页数据。

(2)通用性问题,我们写分页时,不能一直有相同的重复代码。最好封装起来。在任何页面都可以用。

多余的就不说了。写这文章之前,也参考了网上写的比较好的例子。那么我就来总结一下吧。

一种方式
首先:建立一个Web用户控件(为了通用性嘛),代码如下:


 1 <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Pager3.ascx.cs" Inherits="PageS.Pager" %>
 2
 3
 4                 <asp:LinkButton ID="hylfirst" runat="server" onclick="reBind_Click">首页</asp:LinkButton>
 5                 <asp:LinkButton ID="hylprev" runat="server" onclick="reBind_Click">上一页</asp:LinkButton>
 6                 <asp:LinkButton ID="hylnext" runat="server" onclick="reBind_Click">下一页</asp:LinkButton>
 7                 <asp:LinkButton ID="hylend" runat="server" onclick="reBind_Click">尾页</asp:LinkButton>
 8                
 9                 共<asp:Label ID="lbRecord" runat="server" Text="Label"></asp:Label>条记录
10                 共<asp:Label ID="lbpage" runat="server" Text="Label"></asp:Label>页
11                 当前为第<asp:Label ID="lbRow" runat="server" Text=""></asp:Label>页后台:


 1  //当前页码
 2         private int _pageindex;
 3         public int PageIndex
 4         {
 5             get
 6             {
 7                 if (_pageindex == 0)
 8                 {
 9                     _pageindex = 1;
10                 }
11                 return _pageindex;
12             }
13             set { _pageindex = value; }
14         }
15         //一页的大小
16         private int _pageSize;
17         public int PageSize
18         {
19             get
20             {
21                 if (_pageSize == 0)
22                 {
23                     _pageSize = 1;
24                 }
25                 return _pageSize;
26             }
27             set { _pageSize = value; }
28         }
29         //总记录数
30         private int _recordCount;
31         public int RecordCount
32         {
33             get { return _recordCount; }
34             set { _recordCount = value; }
35         }           
36
37         protected void Page_Load(object sender, EventArgs e)
38         {
39             if (!IsPostBack)
40             {
41                 LoadDataBind();
42             }
43         }
44         //绑定
45         public void LoadDataBind()
46         {
47             int pageCount = (RecordCount % PageSize) == 0 ? RecordCount / PageSize : RecordCount / PageSize + 1;//页数
48          
49             initialization(pageCount);
50         }
51         //数据初始化
52         private void initialization(int pageCount)
53         {
54             //--------求出总记录数
55             lbRecord.Text = RecordCount.ToString();
56             //--------当前为第几页
57             lbRow.Text = PageIndex.ToString();
58             //--------共多少页     
59             lbpage.Text = pageCount.ToString();
60
61             this.hylfirst.Enabled = true;
62             this.hylprev.Enabled = true;
63             this.hylnext.Enabled = true;
64             this.hylend.Enabled = true;
65
66             if (Convert.ToInt32(this.lbRow.Text) == 1)
67             {
68                 this.hylfirst.Enabled = false;
69                 this.hylprev.Enabled = false;
70             }
71             if (Convert.ToInt32(this.lbRow.Text) == pageCount)
72             {
73                 this.hylnext.Enabled = false;
74                 this.hylend.Enabled = false;
75             }
76
77             this.hylfirst.CommandArgument = "1";
78             this.hylprev.CommandArgument = (PageIndex - 1).ToString();
79             this.hylnext.CommandArgument = (PageIndex + 1).ToString();
80             this.hylend.CommandArgument = pageCount.ToString();
81
82         }
83
84         //定义一个委托
85         public delegate void reBindEvent(object sender, EventArgs arg);
86         public event reBindEvent reBind;
87
88         protected void reBind_Click(object sender, EventArgs e)
89         {
90             if (this.reBind != null)
91                 this.reBind(sender, e);
92             LoadDataBind();
93         }

说明:在代码的最后利用了委托和事件。这是为什么呢。因为我们在点击自定义控件的按扭(上一页,下一页,首页,未页.....)时,要调用Aspx页面绑定数据的方法。我们在这里不能直接实例化aspx页面类,再去调用其方法。

我们为了通用必须这样去做。有关ASPX和自定义控件之间的赋值,互相调用,大家可以去网上找此资料来看,本章不讲解这些内容。

好了,我们已经做好通用性了,那么我们如何调用呢。

 

建立一个测试页面,代码如下:


 1 <%@ Register src="Pager.ascx" tagname="Pager" tagprefix="uc1" %>
 2
 3
 4
 5 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 6
 7 <html xmlns="http://www.w3.org/1999/xhtml" >
 8 <head runat="server">
 9     <title>利用反射机制</title>
10 </head>
11 <body>
12     <form id="form1" runat="server">
13     <div>
14         <asp:GridView ID="gvUsers" runat="server" ></asp:GridView>    
15         <uc1:Pager ID="Pager1" runat="server" OnreBind="LoadData" />
16            
17     </div>
18  
19       
20     </form>
21 </body>
22 </html>后台:


 1    protected void Page_Load(object sender, EventArgs e)
 2         {
 3             if (!IsPostBack)
 4             {            
 5                 LoadData(null,null);
 6             }
 7         }
 8         protected void LoadData(object sender, EventArgs e)
 9         {
10             if (sender != null)
11             {
12                 Pager1.PageIndex = Convert.ToInt32(((LinkButton)sender).CommandArgument);
13             }
14             else
15             {
16                 Pager1.PageIndex = 1;
17             }
18             int recordcount = 0;
19             Pager1.PageSize = 20;
20           
21             DataTable tables=new DataTable();
22            
23             //通过当前页码,页大小,去数据库调用本页的数据,并且返回总记录数
24             //tables=  BLL.GetCurrentPageData(Pager1.PageIndex, Pager1.PageSize,out count);          
25            
26             gvUsers.DataSource = tables;
27             gvUsers.DataBind();
28             Pager1.RecordCount = recordcount;
29
30
31         }说明: <uc1:Pager ID="Pager1" runat="server" OnreBind="LoadData" /> 看到OnreBind="LoadData"了吗, 这个是我们在自定义控件中定义的事件。在这个订阅一下。

以便在自定义控件中点击按扭时,自动来触发这个事件。从而调用LoadData这个方法。

说了半天,好像还没出给出数据库分页的通用存储过程来。

好了,那我也直接粘出来供大家来分享吧。单表的通用分页存储过程


CREATE PROCEDURE [dbo].[_tgy_BaseGetPageList]
(
    @tblName varchar(255),             -- 表名
    @strGetFields varchar(1000) = '*',     -- 需要返回的列
    @fldName varchar(255) = '',         -- 排序的字段名
    @PageSize int = 10,             -- 页尺寸
    @PageIndex int = 1,             -- 页码
    @doCount bit = 0,             -- 返回记录总数, 非 0 值则返回
    @OrderType bit = 0,             -- 设置排序类型, 非 0 值则降序
    @strWhere varchar(1500) = ''        -- 查询条件 (注意: 不要加 where)
)
AS
  declare @strSQL varchar(5000) -- 主语句
  declare @strTmp varchar(110) -- 临时变量
  declare @strOrder varchar(400) -- 排序类型

  if @doCount != 0
    begin
        if @strWhere !=''
              set @strSQL = 'select count(*) as Total from ' + @tblName + ' where ' + @strWhere
        else
              set @strSQL = 'select count(*) as Total from ' + @tblName + ''
        end
 
    --以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况:

  else
        begin
        if @OrderType != 0
            begin
                set @strOrder = ' order by ' + @fldName + ' desc'
                --如果@OrderType不是0,就执行降序,这句很重要!
            end
        else
            begin
                set @strOrder = ' order by ' + @fldName
            end

        if (@PageIndex = 1 or @PageIndex = 0)
            begin
                if @strWhere != ''
                    set @strSQL = 'select top ' + str(@PageSize) + ' '
                        + @strGetFields
                        + 'from ' + @tblName
                        + ' where ' + @strWhere
                        + ' ' + @strOrder
                else
                    set @strSQL = 'select top ' + str(@PageSize) + ' '
                        + @strGetFields
                        + 'from ' + @tblName
                        + ' ' + @strOrder
            --如果是第一页就执行以上代码,这样会加快执行速度
            end
        else
            begin
            --以下代码赋予了@strSQL以真正执行的SQL代码 
                set @strSQL = 'select top ' + str(@PageSize) + ' '
                            + @strGetFields
                            + ' from '
                            + ' ( select '+ @strGetFields
                            + ' ,Row_Number() OVER('+@strOrder+') as row'
                            + ' from ' + @tblName
                            + ' ) aaa'
                            + ' where row > ' + str((@PageIndex-1)*@PageSize)
                if @strWhere != ''
                    set @strSQL = 'select top ' + str(@PageSize) + ' '
                                + @strGetFields
                                + ' from '
                                + ' ( select '+ @strGetFields
                                + ' ,Row_Number() OVER('+@strOrder+') as row'
                                + ' from ' + @tblName
                                + ' where ' + @strWhere + ' ) aaa'
                                + ' where row > ' + str((@PageIndex-1)*@PageSize)
            end

    end

exec (@strSQL)有的人一看,怎么就针对一张表呢,我在写存储过程的时候很多时候会涉及多张表,这个也不通用呀。好了,毕竟网上有能人。我直接粘下代码。多表通用分页存储过程


  1 CREATE PROCEDURE [dbo].[Proc_SplitPage]  
  2 ( 
  3 @tblName     nvarchar(200),        ----要显示的表或多个表的连接 
  4 @fldName     nvarchar(1000) = '*',    ----要显示的字段列表 
  5 @pageSize    int = 10,        ----每页显示的记录个数 
  6 @page        int = 1,        ----要显示那一页的记录 
  7 @fldSort    nvarchar(200),    ----排序字段列表或条件 
  8 @Sort        bit = 0,        ----排序方法,0为升序,1为降序(如果是多字段排列Sort指代最后一个排序字段的排列顺序(最后一个排序字段不加排序标记)--程序传参如:' SortA Asc,SortB Desc,SortC ') 
  9 @strCondition    nvarchar(2000) = null,    ----查询条件,不需where 
 10 @ID        nvarchar(150),        ----主表的主键 
 11 @Dist                 bit = 0,           ----是否添加查询字段的 DISTINCT 默认0不添加/1添加 
 12 @pageCount    int = 1 output,            ----查询结果分页后的总页数 
 13 @Counts    int = 1 output              ----查询到的记录数 
 14 ) 
 15 AS 
 16 SET NOCOUNT ON 
 17 Declare @sqlTmp nvarchar(1000)        ----存放动态生成的SQL语句 
 18 Declare @strTmp nvarchar(4000)        ----存放取得查询结果总数的查询语句 
 19 Declare @strID     nvarchar(1000)        ----存放取得查询开头或结尾ID的查询语句 
 20  
 21 Declare @strSortType nvarchar(10)    ----数据排序规则A 
 22 Declare @strFSortType nvarchar(10)    ----数据排序规则B 
 23  
 24 Declare @SqlSelect nvarchar(50)         ----对含有DISTINCT的查询进行SQL构造 
 25 Declare @SqlCounts nvarchar(50)          ----对含有DISTINCT的总数查询进行SQL构造 
 26  
 27  
 28 if @Dist  = 0 
 29 begin 
 30     set @SqlSelect = 'select ' 
 31     set @SqlCounts = 'Count(*)' 
 32 end 
 33 else 
 34 begin 
 35     set @SqlSelect = 'select distinct ' 
 36     set @SqlCounts = 'Count(DISTINCT '+@ID+')' 
 37 end 
 38  
 39  
 40 if @Sort=0 
 41 begin 
 42     set @strFSortType=' ASC ' 
 43     set @strSortType=' DESC ' 
 44 end 
 45 else 
 46 begin 
 47     set @strFSortType=' DESC ' 
 48     set @strSortType=' ASC ' 
 49 end 
 50  
 51 --------生成查询语句-------- 
 52 --此处@strTmp为取得查询结果数量的语句 
 53 if @strCondition is null or @strCondition=''     --没有设置显示条件 
 54 begin 
 55     set @sqlTmp =  @fldName + ' From ' + @tblName 
 56     set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName 
 57     set @strID = ' From ' + @tblName 
 58 end 
 59 else 
 60 begin 
 61     set @sqlTmp = + @fldName + 'From ' + @tblName + ' where (1>0) ' + @strCondition 
 62     set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName + ' where (1>0) ' + @strCondition 
 63     set @strID = ' From ' + @tblName + ' where (1>0) ' + @strCondition 
 64 end 
 65  
 66  
 67  
 68 ----取得查询结果总数量----- 
 69 exec sp_executesql @strTmp,N'@Counts int out ',@Counts out 
 70 declare @tmpCounts int 
 71 if @Counts = 0 
 72     set @tmpCounts = 1 
 73 else 
 74     set @tmpCounts = @Counts 
 75  
 76     --取得分页总数 
 77     set @pageCount=(@tmpCounts+@pageSize-1)/@pageSize 
 78  
 79     /**//**当前页大于总页数 取最后一页**/ 
 80     if @page>@pageCount 
 81         set @page=@pageCount 
 82  
 83     --/*-----数据分页2分处理-------*/ 
 84     declare @pageIndex int --总数/页大小 
 85     declare @lastcount int --总数%页大小  
 86  
 87     set @pageIndex = @tmpCounts/@pageSize 
 88     set @lastcount = @tmpCounts%@pageSize 
 89     if @lastcount > 0 
 90         set @pageIndex = @pageIndex + 1 
 91     else 
 92         set @lastcount = @pagesize 
 93  
 94     --//***显示分页 
 95     if @strCondition is null or @strCondition=''     --没有设置显示条件 
 96     begin 
 97         if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2   --前半部分数据处理 
 98             begin  
 99                 set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName 
100                         +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName 
101                         +' order by '+ @fldSort +' '+ @strFSortType+')' 
102                         +' order by '+ @fldSort +' '+ @strFSortType  
103             end 
104         else 
105             begin 
106             set @page = @pageIndex-@page+1 --后半部分数据处理 
107                 if @page <= 1 --最后一页数据显示 
108                     set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@lastcount as VARCHAR(4))+' '+ @fldName+' from '+@tblName 
109                         +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType  
110                 else                 
111                     set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName 
112                         +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName 
113                         +' order by '+ @fldSort +' '+ @strSortType+')' 
114  
115                         +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType  
116             end 
117     end 
118  
119     else --有查询条件 
120     begin 
121         if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2   --前半部分数据处理 
122         begin  
123                 set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName +' from  '+@tblName 
124                     +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName 
125                     +' Where (1>0) ' + @strCondition + ' order by '+ @fldSort +' '+ @strFSortType+')' 
126                     +' ' + @strCondition + ' order by '+ @fldSort +' '+ @strFSortType                  
127         end 
128         else 
129         begin  
130             set @page = @pageIndex-@page+1 --后半部分数据处理 
131             if @page <= 1 --最后一页数据显示 
132                     set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@lastcount as VARCHAR(4))+' '+ @fldName+' from '+@tblName 
133                         +' where (1>0) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType 
134             else 
135                     set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName 
136                         +' where '+@ID+' not in('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName 
137                         +' where (1>0) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+')' 
138                         + @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType  
139         end     
140     end 
141  
142 ------返回查询结果----- 
143 exec sp_executesql @strTmp   
144 --print @strTmp 
145 SET NOCOUNT OFF 
146   

 本文就更新到这里,后台也会有我其它的分页实现,以上代码中涉及自定义控件调用aspx类的方法,其实也可以用反射机制来实现,大家试试吧。以后我也会涉及。可能也有人对怎么使用通用存储过程也有疑问,我也会在接下来的几篇文章中细讲。

Ok,本文结束:

来源:http://www.cnblogs.com/yxhblog/archive/2012/06/29/2570020.html

« 上一篇下一篇 »

评论列表:

1.风机盘管  2012/7/24 8:50:32 回复该留言
在任何页面都可以用。
2.风机盘管  2012/7/24 8:51:01 回复该留言
我们在这里不能直接实例化aspx页面类,再去调用其方法。
3.地源热泵  2012/7/24 8:51:44 回复该留言
只是给刚接触分页和不是很了解分页的查看一下。
4.地源热泵  2012/7/24 8:52:32 回复该留言
大家可能不会很陌生,如果做过ASP.NET的

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。