使用ASP.NET开发web程序时,经常会遇到数据列表页需要分页的问题。在ASP.NET里,分页可以通过绑定数据控件实现,如GridView、DataList、Repeater、ListView等这些数据控件都可以实现分页效果。它们之间的一些对比:
GridView:开发效率高,自带分页、排序、但占用资源高。
DataList:分页和排序需要手动编码,分页需要使用 PagedDataSource类实现。
Repeater:不提供任何布局,开发周期长。
注意,使用这些控件的时候,ViewState功能必须打开(即 EnableViewState="true" 在NET里,默认是打开的),因为如果关闭了ViewState视图状态,在点击下一页这些跳转按钮时,.net页面是记不住当前状态的。
但是,重点来了:
这些使用控件的分页方法基本是采用了javascript的方法实现的跳转:
比如 DataList 配合 PagedDataSource类实现的代码如下:
代码如下 |
复制代码 |
下一页
GridView自带的分页代码如下:
第2页 |
而我们知道,作为web网站程序开发,seo/seo.html" target="_blank">搜索引擎对页面的(前台)js的链接并不敏感,也不会抓取和索引js里的链接,这就会造成一个严重的情况,那就是列表页从第二页开始,都无法抓取并索引,大量网页无法出现在搜索引擎的结果页里。
因此,飘易设计了一个比较通用的高效率的asp.net分页算法的实现,实现方法如下:
在 default.aspx 前台页面里放入代码(注意,必须添加 runat="server" 标记):
在 default.aspx.cs 后台代码页面里编写代码:
代码如下 |
复制代码 |
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Data.SqlClient;
public partial class _Default: System.Web.UI.Page
{
comClass CC = new comClass();//实例化
protected void Page_Load(object sender, EventArgs e)
{//初始化
if (!IsPostBack)
{
string html = getListData();
divlist.InnerHtml = html;
}
}
public static bool IsNum(String str)
{//判断是否是ASCII纯数字
if (str == null || str == "") return false;
for (int i = 0; i < str.Length; i++)
{
if (str[i] < '0' || str[i] > '9')
return false;
}
return true;
}
public string getListData()
{//绑定数据
string html = "";
SqlConnection conn = CC.getConn();
conn.Open();
SqlCommand cmd;
SqlDataReader dr;
try
{
int page = 1;
string page_get = Request["page"]; //获取当前页
if (IsNum(page_get)) page = Convert.ToInt32(page_get);
int pagesize = 5; //每页多少个
int TotalRecords, TotalPages;
//总记录数
cmd = new SqlCommand("select count(*) from data ", conn);
dr = cmd.ExecuteReader();
dr.Read();
TotalRecords = Int32.Parse(dr[0].ToString());
dr.Close();
cmd.Dispose();
//总页数
if (TotalRecords % pagesize == 0) TotalPages = TotalRecords / pagesize;
else TotalPages = TotalRecords / pagesize + 1;
//当前页
if (page < 1) page = 1;
if (page > TotalPages) page = TotalPages;
//---核心分页算法---
string sql = "select top " + pagesize + " * from data order by id desc";
if (page > 1) sql = "select top " + pagesize + " * from data where id<(SELECT Min(id) FROM (SELECT TOP " + pagesize * (page - 1) + " id FROM data ORDER BY id desc) AS T) order by id desc";
cmd = new SqlCommand(sql, conn);
dr = cmd.ExecuteReader();
while (dr.Read())
{
html += dr["id"].ToString() + "、" + dr["title"].ToString() + " ";
}
dr.Close();
cmd.Dispose();
//分页代码
string cfile = Request.Path; //当前请求的虚拟路径
string pagestr = "rn 首页 ";
for (int i=1; i<=TotalPages ; i++ )
{
if (i == page) pagestr += " " + i + " ";
else
{
if (Math.Abs(page - i) < 8)
{
if (i == 1) pagestr += " " + i + " ";
else pagestr += " " + i + " ";
}
}
}
pagestr += " 尾页 ";
pagestr += " 第" + page + "/" + TotalPages + "页, 总共" + TotalRecords + "条 ";
html += pagestr;
}
catch (Exception ex) { html = "异常错误:" + ex.ToString(); }
finally { conn.Close(); }
return html;
}
}
|
存储过程分页法
OK,我们首先创建一数据库:data_Test,并在此数据库中创建一表:tb_TestTable
1create database data_Test --创建数据库data_Test
2GO
3use data_Test
4GO
5create table tb_TestTable --创建表
6(
id int identity(1,1) primary key,
userName nvarchar(20) not null,
userPWD nvarchar(20) not null,
userEmail nvarchar(40) null
11)
12GO
然后我们在数据表中插入2000000条数据:
1--插入数据
2set identity_insert tb_TestTable on
3declare @count int
4set @count=1
5while @count<=2000000
6begin
insert into tb_TestTable(id,userName,userPWD,userEmail) values(@count,'admin','admin888','[email protected]')
set @count=@count+1
9end
10set identity_insert tb_TestTable off
下面是2分法使用select max的代码,已相当完善。
代码如下 |
复制代码 |
1--/*-----存储过程 分页处理 孙伟 2005-03-28创建 -------*/
2--/*-----存储过程 分页处理 浪尘 2008-9-1修改----------*/
3--/*----- 对数据进行了2分处理使查询前半部分数据与查询后半部分数据性能相同 -------*/
5alter PROCEDURE proc_paged_2part_selectMax
6(
7@tblName nvarchar(200), ----要显示的表或多个表的连接
8@fldName nvarchar(500) = '*', ----要显示的字段列表
9@pageSize int = 10, ----每页显示的记录个数
10@page int = 1, ----要显示那一页的记录
11@fldSort nvarchar(200) = null, ----排序字段列表或条件
12@Sort bit = 0, ----排序方法,0为升序,1为降序(如果是多字段排列Sort指代最后一个排序字段的排列顺序(最后一个排序字段不加排序标记)--程序传参如:' SortA Asc,SortB Desc,SortC ')
13@strCondition nvarchar(1000) = null, ----查询条件,不需where
14@ID nvarchar(150), ----主表的主键
15@Dist bit = 0, ----是否添加查询字段的 DISTINCT 默认0不添加/1添加
16@pageCount int = 1 output, ----查询结果分页后的总页数
17@Counts int = 1 output ----查询到的记录数
18)
19AS
20SET NOCOUNT ON
21Declare @sqlTmp nvarchar(1000) ----存放动态生成的SQL语句
22Declare @strTmp nvarchar(1000) ----存放取得查询结果总数的查询语句
23Declare @strID nvarchar(1000) ----存放取得查询开头或结尾ID的查询语句
25Declare @strSortType nvarchar(10) ----数据排序规则A
26Declare @strFSortType nvarchar(10) ----数据排序规则B
28Declare @SqlSelect nvarchar(50) ----对含有DISTINCT的查询进行SQL构造
29Declare @SqlCounts nvarchar(50) ----对含有DISTINCT的总数查询进行SQL构造
31declare @timediff datetime --耗时测试时间差
32select @timediff=getdate()
34if @Dist = 0
35begin
set @SqlSelect = 'select '
set @SqlCounts = 'Count(*)'
38end
39else
40begin
set @SqlSelect = 'select distinct '
set @SqlCounts = 'Count(DISTINCT '+@ID+')'
43end
45
46if @Sort=0
47begin
set @strFSortType=' ASC '
set @strSortType=' DESC '
50end
51else
52begin
set @strFSortType=' DESC '
set @strSortType=' ASC '
55end
57
59--------生成查询语句--------
60--此处@strTmp为取得查询结果数量的语句
61if @strCondition is null or @strCondition='' --没有设置显示条件
62begin
set @sqlTmp = @fldName + ' From ' + @tblName
set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName
set @strID = ' From ' + @tblName
66end
67else
68begin
set @sqlTmp = + @fldName + 'From ' + @tblName + ' where (1>0) ' + @strCondition
set @strTmp = @SqlSelect+' @Counts='+@SqlCounts+' FROM '+@tblName + ' where (1>0) ' + @strCondition
set @strID = ' From ' + @tblName + ' where (1>0) ' + @strCondition
72end
74----取得查询结果总数量-----
75exec sp_executesql @strTmp,N'@Counts int out ',@Counts out
76declare @tmpCounts int
77if @Counts = 0
set @tmpCounts = 1
79else
set @tmpCounts = @Counts
82 --取得分页总数
set @pageCount=(@tmpCounts+@pageSize-1)/@pageSize
85 /**//**//**//**当前页大于总页数 取最后一页**/
if @page>@pageCount
set @page=@pageCount
89 --/*-----数据分页2分处理-------*/
declare @pageIndex int --总数/页大小
declare @lastcount int --总数%页大小
93 set @pageIndex = @tmpCounts/@pageSize
set @lastcount = @tmpCounts%@pageSize
if @lastcount > 0
set @pageIndex = @pageIndex + 1
else
set @lastcount = @pagesize
100 --//***显示分页
if @strCondition is null or @strCondition='' --没有设置显示条件
begin
if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2 --前半部分数据处理
begin
if @page=1
set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' order by '+ @fldSort +' '+ @strFSortType
else
begin
if @Sort=1
begin
set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' <(select min('+ @ID +') from ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName
+' order by '+ @fldSort +' '+ @strFSortType+') AS TBMinID)'
+' order by '+ @fldSort +' '+ @strFSortType
end
else
begin
set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' >(select max('+ @ID +') from ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName
+' order by '+ @fldSort +' '+ @strFSortType+') AS TBMinID)'
+' order by '+ @fldSort +' '+ @strFSortType
end
end
end
else
begin
set @page = @pageIndex-@page+1 --后半部分数据处理
if @page <= 1 --最后一页数据显示
set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@lastcount as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
else
if @Sort=1
begin
set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' >(select max('+ @ID +') from('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName
+' order by '+ @fldSort +' '+ @strSortType+') AS TBMaxID)'
+' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
end
else
begin
set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' <(select min('+ @ID +') from('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName
+' order by '+ @fldSort +' '+ @strSortType+') AS TBMaxID)'
+' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
end
end
end
150 else --有查询条件
begin
if @pageIndex<2 or @page<=@pageIndex / 2 + @pageIndex % 2 --前半部分数据处理
begin
if @page=1
set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where 1=1 ' + @strCondition + ' order by '+ @fldSort +' '+ @strFSortType
else if(@Sort=1)
begin
set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' <(select min('+ @ID +') from ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName
+' where (1=1) ' + @strCondition +' order by '+ @fldSort +' '+ @strFSortType+') AS TBMinID)'
+' '+ @strCondition +' order by '+ @fldSort +' '+ @strFSortType
end
else
begin
set @strTmp=@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' >(select max('+ @ID +') from ('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-1) as Varchar(20)) +' '+ @ID +' from '+@tblName
+' where (1=1) ' + @strCondition +' order by '+ @fldSort +' '+ @strFSortType+') AS TBMinID)'
+' '+ @strCondition +' order by '+ @fldSort +' '+ @strFSortType
end
end
else
begin
set @page = @pageIndex-@page+1 --后半部分数据处理
if @page <= 1 --最后一页数据显示
set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@lastcount as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where (1=1) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
else if(@Sort=1)
set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' >(select max('+ @ID +') from('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName
+' where (1=1) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TBMaxID)'
+' '+ @strCondition+' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
else
set @strTmp=@SqlSelect+' * from ('+@SqlSelect+' top '+ CAST(@pageSize as VARCHAR(4))+' '+ @fldName+' from '+@tblName
+' where '+@ID+' <(select min('+ @ID +') from('+ @SqlSelect+' top '+ CAST(@pageSize*(@page-2)+@lastcount as Varchar(20)) +' '+ @ID +' from '+@tblName
+' where (1=1) '+ @strCondition +' order by '+ @fldSort +' '+ @strSortType+') AS TBMaxID)'
+' '+ @strCondition+' order by '+ @fldSort +' '+ @strSortType+') AS TempTB'+' order by '+ @fldSort +' '+ @strFSortType
end
end
191------返回查询结果-----
192exec sp_executesql @strTmp
193select datediff(ms,@timediff,getdate()) as 耗时
194--print @strTmp
195SET NOCOUNT OFF
196GO
|