一说到“分页”,大家可能不会很陌生,如果做过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
评论列表: