这个例子展示如何使用SQL Server 2005 的ROW_NUMBER功能去分页,以及通过在code-behind中自定义HTML输出比较好看的界面。
首先,我们必须去选择的列表记录,通常使用的分页技术是我们将所有的记录放入一个dataset,然后使用PagedDataSource来显示适当的页。这种技术主要不好的地方是在内存中存储了所有的记录,而在页面上仅仅显示其中的一些记录。每次你点击页码,每次它都将查询了所有的记录。为了克服这个头痛的问题,我将有效地使用SQL Server 2005的ROW_NUMBER 功能。
我们将传递两个参数,存储过程能查询特定的记录。
@intCurrentPage int
- 这个参数用来表示当前页码。
@intRecordPerPage int
- 这个参数用来得到一页中显示的记录数量。
例如,如果我们将 @intCurrentPage设置为1
,将@intRecordPerPage设置为10,结果将会是1到10的记录。 这个存储过程连接到AdventureWorks数据库,从Production.Product 查询记录。
代码
SET
ANSI_NULLS
ON
GO
SET
QUOTED_IDENTIFIER
ON
GO
--
=============================================
--
Author:
--
Create date: 24-12-2009
--
Description: To get specific records from product table
--
of AdventureWorks database.
--
=============================================
set
ANSI_NULLS
ON
set
QUOTED_IDENTIFIER
ON
go
CREATE
PROCEDURE
[
dbo
]
.
[
uspFetchProduct
]
@intCurrentPage
int
,
@intRecordPerPage
int
AS
BEGIN
SET
NOCOUNT
ON
;
--
***Find the starting record id and ending record id ****
declare
@intStartRec
int
set
@intStartRec
=
(
@intCurrentPage
*
@intRecordPerPage
)
-
@intRecordPerPage
declare
@intEndRec
int
set
@intEndRec
=
(
@intCurrentPage
*
@intRecordPerPage
)
+
1
--
********************************************************
Begin
--
***Select the records from @intStartRec to @intEndRec ***
Select
*
from
(
select
ROW_NUMBER()
OVER
(
ORDER
BY
ProductID)
as
SlNo,ProductID,
[
Name
]
,ProductNumber,StandardCost
from
Production.Product
)
Temp
Where
SlNo
>
@intStartRec
and
SlNo
<
@intEndRec
--
***********************************************************
--
***Get the total number of records***************
select
COUNT
(ProductID)
as
TotalRecords
from
Production.Product
--
************************************************
End
END
通过传递:@intCurrentPage=1, @intRecordPerPage=10,执行上面的存储过程。
第一个结果集是第一页的记录,第二个结果集是记录的总和。
在AdventureWorks 数据库中执行这个存储过程,创建一个连接字符串来连接AdventureWorks。
connectionString
=
"Data Source
=
[
SERVER NAME
]
;
Initial Catalog
=
AdventureWorks;
User
ID
=
[
USERNAME
]
; Password
=
[
PASSWORD
]
"
/>
现在我们在数据库中准备好存储过程,开始实现我们的列表和分页方法。 为了显示列表,我将不使用任何数据源控件,我将直接在aspx页面上输出。对于这个,在后台代码中,我们首先定义两个字符串。
protected
string
strList;
//
to set the HTML of the listing
protected
string
strPages;
//
to set the HTML of paging
字符串变量strList 用来保存记录的列表的HTML,strPages 用来保存分页的HTML。首先,我必须得到页的索引,我将页的索引存放在隐藏的文本字段中(txtHidPageIndex)。默认,第一页将被显示。我们将用户点击的页索引,将它存储在这个隐藏字段中 ,服务端能访问这个隐藏字段来获得页码。我们需要一个服务端控件来监听页面的点击。 我在页面上添加一个link button控件(lnkPaging)来初始化clicking,它也能完成一些服务端的动作。
写一个javascript函数来接受页码和将页码以及将它放到隐藏字段中。 在此之后,执行link button的回传,这样我们能执行服务端的操作。该链接按钮的Click事件可以发起的ASP.NET doPostBack方法。
function
doPaging(intPageIndex)
{
document.getElementById(
'
txtHidPageIndex
'
).value
=
intPageIndex;
__doPostBack(
'
lnkPaging
'
,
''
);
}
link button (lnkPaging
) 的后台代码如下:
protected
void
lnkPaging_Click(
object
sender, EventArgs e)
{
DoSearch(
int
.Parse(txtHidPageIndex.Value));
}
下面的片段显示如何将记录填充到reader中。
代码
private
void
DoSearch(
int
intPageIndex)
//
{
//
**The number of records in one page
int
intRecordPerPage
=
10
;
SqlConnection objCon
=
new
SqlConnection(ConfigurationManager.ConnectionStrings[
"
ConString
"
].ConnectionString);
SqlCommand objCmd
=
new
SqlCommand();
objCmd.Connection
=
objCon;
SqlDataReader objReader ;
objCmd.CommandType
=
CommandType.StoredProcedure;
objCmd.CommandText
=
"
uspFetchProduct
"
;
objCmd.Parameters.Add(
new
SqlParameter(
"
@intCurrentPage
"
, intPageIndex));
objCmd.Parameters.Add(
new
SqlParameter(
"
@intRecordPerPage
"
, intRecordPerPage));
objCon.Open();
objReader
=
objCmd.ExecuteReader(CommandBehavior.CloseConnection);
我设置一页显示10条记录。如果你想让用户自定义每页的记录数量,在你的网站中,你能添加一个选项设置值。用这个值来作为每页显示的记录数量。现在,我们在reader已经有了结果。创建一个StringBuilder 来存储创建的 HTML 。
代码
StringBuilder sbHTML
=
new
StringBuilder();
//
**********HEADER*********************
sbHTML.Append(
"
<table><tr><td class='header'>SlNo</td><td class='header'>ProductID</td><td class='header'>Name</td><td class='header'>ProductNumber</td><td class='header'>StandardCost</td></tr>
"
);
//
**********END HEADER*****************
//
***********LIST**********************
bool
bRecordFound
=
false
;
while
(objReader.Read()) {
bRecordFound
=
true
;
sbHTML.Append(
"
<tr>
"
);
在创建列表的HTML之后,我将它分配给一个保护的变量strList。
strList = sbHTML.ToString();
现在完成我们主要要做的事情:如何去分页。对于分页,首先我们需要所有记录的总数量。能从reader中得到这个数量。
objReader.NextResult();
int
intTotalRecords
=
0
;
if
(objReader.Read()) {
intTotalRecords
=
int
.Parse(objReader[
0
].ToString());
}
现在,intTotalRecords变量包含了记录的总数量。第二个任务是去找页码数量。如下所示:
代码
int
intReminder
=
intTotalRecords
%
intRecordPerPage;
//
(100/10) mod=0 and (105/10) mod=5
int
intTotalPages
=
intTotalRecords
/
intRecordPerPage;
//
(100/10) =10 and 105\10 =10
if
(intReminder
>
0
) {
//
(100/10) so 10 pages, if (105/10) means 11 pages
intTotalPages
+=
1
;
}
现在我们必须去找每一页的开始的一条记录和最后的一条记录。我们假设显示在页码列表中包含5页。 因此用户能获得First和Previous按钮,接下来是下5页的页码按钮,还有Next和Last按钮。
代码
int
intPagesShowing
=
5
;
//
5 pages will be showing in the list (1|2|3|4|5 then show next button)
int
intStartPage
=
0
;
int
intEndPage
=
0
;
intStartPage
=
(intPageIndex
<=
intPagesShowing
?
1
: intPageIndex);
if
(intTotalPages
>
intPagesShowing
&
intTotalPages
>
intStartPage) {
intEndPage
=
((intStartPage
+
intPagesShowing
-
1
)
>
intTotalPages
?
intTotalPages : (intStartPage
+
intPagesShowing
-
1
));
}
else
{
intEndPage
=
intTotalPages;
}
现在,我们要能通过页的索引和剩余的记录数目来隐藏和禁用First, Previous, Next, 和Last button。
代码
bool
bShowFirst
=
false
;
bool
bShowPrevious
=
false
;
bool
bShowNext
=
false
;
bool
bShowLast
=
false
;
if
(intPageIndex
>
1
) {
bShowPrevious
=
true
;
bShowFirst
=
true
;
}
if
(intEndPage
<
intTotalPages) {
bShowNext
=
true
;
bShowLast
=
true
;
}
现在,我们能添加一个页数,它从第一页到最后一页。
代码
for
(
int
iPage
=
intStartPage; iPage
<=
intEndPage; iPage
++
) {
//
page numbers from current page to next recordsperpage (ie. 1-10)
if
(intPageIndex
==
iPage) {
sbHTML.Append(
"
<li class='active'>
"
);
sbHTML.Append(
"
<a>
"
);
}
else
{
sbHTML.Append(
"
<li>
"
);
sbHTML.Append(
"
<a style='cursor:hand' onClick='javascript:doPaging(
"
);
sbHTML.Append(iPage.ToString());
sbHTML.Append(
"
);'>
"
);
}
sbHTML.Append(iPage.ToString());
sbHTML.Append(
"
</a></li>
"
);
}
在实现了分页的HTML之后,在protected类型的字符串strPages中存储StringBuilder类型的值。分页就是就是如果页数超过一页,就仅仅显示一页。
代码
if
(intTotalPages
>
1
) {
//
no paging is needed if only one page
strPages
=
sbHTML.ToString();
//
***********END PAGING************************************************************
//
===============================================================================================================
}
如果使用这个方法,你不需要任何的数据源控件。我们创建和管理列表和分页的HTML。这项技术在你的页面上将给你带来最大的灵活性。