ASP.NET数据分页的多种实现方法及性能比较
导言:
动态网站设计者们遇到的最常见的问题就是给数据库里面的数据分页。数据库里面杂乱无章的数据是没有价值的,如果我们没有给这些数据分明别类的统计、分页的话。所以,作为一个动态网页的设计者,我们必须提供给访问者尽可能任意阅读和认知的内容,而给数据分页就是最基本的要求。
数据分页其实不是什么新话题,所有的搜索引擎网站和电子商务网站几乎都有这个功能。我们试着用搜索词ASP搜索一下Google.com,我们会得到500万个结果!想象一下,如果Goole将这500万个结果一下子通过一个网页给我们,那个网页是多么地巨大和杂乱,所以,Google将这些数据进行了分页,每页10条记录。
本文将介绍在ASP.NET中怎样实现将数据库中的内容进行数据分页。要实现分页惊人的简单,只要几行代码就可以做到。
ASP中的数据分页
在ASP中,要实现数据分页可以有很多途径。其中最常用的一个方法就是通过ADO RecordSet的属性实现数据分页,然而,即使是使用这些属性,设计者们仍然要写许多代码。当然,还有其他途径可以实现数据分页,比如使用存储过程和客户端脚本等方法。所有这些方法都需要设计者书写太多代码,而且,这些ASP代码和HTML混杂在一起,维护和设计都比较麻烦。
ASP.NET中的数据分页
幸运的是,ASP.NET中要实现数据分页比在ASP中简单明了的多,当然,也没有那么多代码要写。这里,我们使用DataGrid实现数据分页,因为DataGrid控件可以自身处理数据分页,所以,我们真正需要编写的代码很少。首先,我们来看一个DataGrid,该DataGrid通过捆绑DataSet得到数据库中的具体数据。
在下面的代码中,你可以看到其中的HTML部分很少,甚至于只要能包含一个DataGrid控件就可以了。我们设置了一些DataGrid的属性来加强DataGrid的外观,当然,这些加强外观的属性设置也可以不要,直接使用控件默认就可以了。
动态网站设计者们遇到的最常见的问题就是给数据库里面的数据分页。数据库里面杂乱无章的数据是没有价值的,如果我们没有给这些数据分明别类的统计、分页的话。所以,作为一个动态网页的设计者,我们必须提供给访问者尽可能任意阅读和认知的内容,而给数据分页就是最基本的要求。
数据分页其实不是什么新话题,所有的搜索引擎网站和电子商务网站几乎都有这个功能。我们试着用搜索词ASP搜索一下Google.com,我们会得到500万个结果!想象一下,如果Goole将这500万个结果一下子通过一个网页给我们,那个网页是多么地巨大和杂乱,所以,Google将这些数据进行了分页,每页10条记录。
本文将介绍在ASP.NET中怎样实现将数据库中的内容进行数据分页。要实现分页惊人的简单,只要几行代码就可以做到。
ASP中的数据分页
在ASP中,要实现数据分页可以有很多途径。其中最常用的一个方法就是通过ADO RecordSet的属性实现数据分页,然而,即使是使用这些属性,设计者们仍然要写许多代码。当然,还有其他途径可以实现数据分页,比如使用存储过程和客户端脚本等方法。所有这些方法都需要设计者书写太多代码,而且,这些ASP代码和HTML混杂在一起,维护和设计都比较麻烦。
ASP.NET中的数据分页
幸运的是,ASP.NET中要实现数据分页比在ASP中简单明了的多,当然,也没有那么多代码要写。这里,我们使用DataGrid实现数据分页,因为DataGrid控件可以自身处理数据分页,所以,我们真正需要编写的代码很少。首先,我们来看一个DataGrid,该DataGrid通过捆绑DataSet得到数据库中的具体数据。
在下面的代码中,你可以看到其中的HTML部分很少,甚至于只要能包含一个DataGrid控件就可以了。我们设置了一些DataGrid的属性来加强DataGrid的外观,当然,这些加强外观的属性设置也可以不要,直接使用控件默认就可以了。
<html>
<body>
<asp:datagrid id="dgPopularFAQs" runat="server" BorderWidth="0"
CellPadding="2" Width="100%"
Font-Name="Verdana"
Font-Size="Smaller"
HeaderStyle-HorizontalAlign="Center"
HeaderStyle-Font-Bold="True"
HeaderStyle-BackColor="Navy"
HeaderStyle-ForeColor="White"
AlternatingItemStyle-BackColor="#dddddd">
</asp:datagrid>
</body>
</html>
<body>
<asp:datagrid id="dgPopularFAQs" runat="server" BorderWidth="0"
CellPadding="2" Width="100%"
Font-Name="Verdana"
Font-Size="Smaller"
HeaderStyle-HorizontalAlign="Center"
HeaderStyle-Font-Bold="True"
HeaderStyle-BackColor="Navy"
HeaderStyle-ForeColor="White"
AlternatingItemStyle-BackColor="#dddddd">
</asp:datagrid>
</body>
</html>
下一步,我们需要编写代码请求数据库中的数据,然后将这些数据放入DataSet,然后,捆绑数据到DataGrid控件,在这里, DataGrid控件是dgPopularFAQs。连接数据库Sql Server 7的代码我们可以在下面看到,如果需要连接其他数据库,可以将下面所有实例的名字中的SQL改为OleDB,比如,将Dim myDA as New SqlDataAdapter() 改为 Dim myDA as New OleDbDataAdapter()。
<% @Import Namespace="System.Data" %>
<% @Import Namespace="System.Data.SqlClient" %>
<script language="vb" runat="server">
Sub Page_Load(sender as Object, e as EventArgs)
BindData()
End Sub
Sub BindData()
'1. 建立连接
Dim myConnection as New SqlConnection(<i>ConnectionString</i>)
'2. 建立Command对象
Const strSQL as String = "SELECT FAQID, Description, DateEntered, ViewCount " & _
"FROM tblFAQ ORDER BY FAQID"
Dim myCommand as New SqlCommand(strSQL, myConnection)
'3.建立DataAdapter
Dim myDA as New SqlDataAdapter()
myDA.SelectCommand = myCommand
'4. 组件DataSet
Dim myDS as New DataSet()
myDA.Fill(myDS)
'5. 捆绑数据
dgPopularFAQs.DataSource = myDS
dgPopularFAQs.DataBind()
End Sub
</script>
<% @Import Namespace="System.Data.SqlClient" %>
<script language="vb" runat="server">
Sub Page_Load(sender as Object, e as EventArgs)
BindData()
End Sub
Sub BindData()
'1. 建立连接
Dim myConnection as New SqlConnection(<i>ConnectionString</i>)
'2. 建立Command对象
Const strSQL as String = "SELECT FAQID, Description, DateEntered, ViewCount " & _
"FROM tblFAQ ORDER BY FAQID"
Dim myCommand as New SqlCommand(strSQL, myConnection)
'3.建立DataAdapter
Dim myDA as New SqlDataAdapter()
myDA.SelectCommand = myCommand
'4. 组件DataSet
Dim myDS as New DataSet()
myDA.Fill(myDS)
'5. 捆绑数据
dgPopularFAQs.DataSource = myDS
dgPopularFAQs.DataBind()
End Sub
</script>
一下是以上代码的运行效果(图一)
需要注意的是,上面代码中ConnectionString必须是合法的SQL数据库连接语句。比如,像以下格式的数据库连接(使用OleDb有一些细微的变化):
server=IPAddress;uid=userName;pwd=password;database=databaseName
以上数据库连接、数据显示通过以下五步实现:
1、 连接到数据库;
2、 通过适当的SQL查询语句建立Command对象;
3、 建立DataAdapter;
4、 通过请求得到的数据组建DataSet;
5、 捆绑DataSet到DataGrid;
我们注意到DataGrid控件很容易就可以通过不错的样式显示数据库里面的数据。仔细看看程序运行结果,我们发现DataGrid控件的外表样式很不错,而这种效果的实现,再也不必像ASP中一样ASP代码和HTML代码相互混杂。
以上只是使用DataGrid控件显示数据库中的所有数据,下面我们对这些数据实现分页。
数据分页的实现
使用DataGrid要实现数据分页,只需要以下简单的几步就可以了:
1、 设置DataGrid控件的AllowPaging为True,其实就是设置DataGrid为允许分页显示;
2、 编写OnPageIndexChanged事件来处理分页请求;
这样就可以了,针对刚才的举例,我们对以上代码中的DataGrid设置相应的属性和相关事件就可以实现数据分页了:
<asp:datagrid id="dgPopularFAQs" runat="server" BorderWidth="0"
CellPadding="2" Width="100%"
Font-Name="Verdana"
Font-Size="Smaller"
AutoGenerateColumns="False"
HeaderStyle-HorizontalAlign="Center"
HeaderStyle-Font-Bold="True"
HeaderStyle-BackColor="Navy"
HeaderStyle-ForeColor="White"
AlternatingItemStyle-BackColor="#dddddd"
AllowPaging="True"
PageSize="15"
OnPageIndexChanged="dgPopularFAQs_Paged">
</asp:datagrid>
CellPadding="2" Width="100%"
Font-Name="Verdana"
Font-Size="Smaller"
AutoGenerateColumns="False"
HeaderStyle-HorizontalAlign="Center"
HeaderStyle-Font-Bold="True"
HeaderStyle-BackColor="Navy"
HeaderStyle-ForeColor="White"
AlternatingItemStyle-BackColor="#dddddd"
AllowPaging="True"
PageSize="15"
OnPageIndexChanged="dgPopularFAQs_Paged">
</asp:datagrid>
在以上代码中,还有一个属性我们需要注意,那就是PageSize。这个属性设置分页以后每页显示数据的条数,在这里,每页显示15条,如果不定义此属性,控件默认为10条。现在,我们需要做的只有定义数据分页事件,当然,这个也比较简单:当用户点击新的页面编号时,将当前的页面编号CurrentPageIndex改为新的页面编号。以下是页面改变事件代码:
<script language="vb" runat="server">
Sub dgPopularFAQs_Paged(sender as Object , e as DataGridPageChangedEventArgs)
dgPopularFAQs.CurrentPageIndex = e.NewPageIndex
BindData()
End Sub
</script>
Sub dgPopularFAQs_Paged(sender as Object , e as DataGridPageChangedEventArgs)
dgPopularFAQs.CurrentPageIndex = e.NewPageIndex
BindData()
End Sub
</script>
需要注意的是,当页面改变以后,我们需要重新绑定数据。相类似的情形,在第一次登载页面的时候,我们需要绑定数据,而以后再次刷新就不要再绑定了:
<script language="vb" runat="server">
Sub Page_Load(sender as Object, e as EventArgs)
If Not Page.IsPostBack then
BindData()
End If
End Sub
</script>
Sub Page_Load(sender as Object, e as EventArgs)
If Not Page.IsPostBack then
BindData()
End If
End Sub
</script>
现在我们来看一个程序运行实例:
我们看到上面的程序已经按照每页15条记录分页,但是,如果你按照我们上面的方法设计,得到的结果虽然可以分页,却不是以上效果。为什么呢,因为我们还增加了一些增强效果,这些效果通过PagerStyle定义,比如以下代码:
<asp:datagrid ...>
<PagerStyle Mode="<i>Mode</i>"
NextPageText="<i>NextPageText</i>" PrevPageText="<i>PrevPageText</i>"
Position="<i>PagePosition</i>">
</PagerStyle>
</asp:datagrid>
<PagerStyle Mode="<i>Mode</i>"
NextPageText="<i>NextPageText</i>" PrevPageText="<i>PrevPageText</i>"
Position="<i>PagePosition</i>">
</PagerStyle>
</asp:datagrid>
以上代码中,Mode(页面模式)可以设置为:NextPrev 或者NumericPages,NextPrev也就是那种“上一页 下一页”的方式,NumericPages是数字方式;Position(页码位置)可以设置为Top, Bottom或者TopAndBottom。
应该知道的
以上实现分页很简单,但是,我们还需要真正了解分页。用户每一次点击新的页面,整个DataSet都要重新构建,如果这个DataSet数据量不是很多当然没有任何问题,但是如果有一个1000条数据的DataSet,每一次请求更改页面都要重新构建,那么,这种途径实现分页就不是很理想了。这时候,我们就不能再使用以上途径来实现分页了,我们可以使用DataGrid的AllowCustomPaging来实现。
DataGrid的AllowCustomPaging
以上我们提到的分页方法,其实只适合数据量比较小的情况,网上很多文章介绍数据分页,也仅仅提到以上的方法。当数据量大的时候,采用以上方法将消耗大量资源,所以,我们必须寻求别的方法解决,最好,每一次改变页面的时候,只是将需要显示的那些页面数据装载到内存,而不是所有页面的数据。
DataGrid的AllowCustomPaging属性可以实现以上功能。首先,我们将DataGrid的AllPaging和AllowCustomPaging属性都设置为True,然后,设置PageIndexChanged事件。
在PageIndexChanged事件中,我们首先要将CurrentPageIndex属性设置为需要显示的页码;然后,构建一个只有一个页面数据的DataSource,然后绑定数据到DataGrid。
当AllowCustomPaging为False的时候,DataGrid假设所有DataSource的数据都要求显示;DataGrid根据CurrentPageIndex和PageSize来决定显示那些数据,其实,这只是选择所有数据中的一部分显示,没显示的数据还在内存中,而且,每一次更换页面,DataGrid都将重新计算意思需要显示的页面数据。
当AllowCustomPaging设置为True的时候,DataGrid根据VirtualItemCount和PageSize属性来决定那些数据需要显示,每次更换页面只装载需要显示的那部分数据。
现在,我们来看一个具体的举例:
<%@ Import Namespace="System.Data" %>
<html>
<script language="VB" runat="server">
Dim start_index As Integer
Function CreateDataSource() As ICollection
Dim dt As New DataTable()
Dim dr As DataRow
dt.Columns.Add(New DataColumn("IntegerValue", GetType(Int32)))
dt.Columns.Add(New DataColumn("StringValue", GetType(String)))
dt.Columns.Add(New DataColumn("CurrencyValue", GetType(Double)))
Dim i As Integer
For i = start_index To (start_index + ItemsGrid.PageSize) - 1
dr = dt.NewRow()
dr(0) = i
dr(1) = "Item " + i.ToString()
dr(2) = 1.23 *(i + 1)
dt.Rows.Add(dr)
Next i
Dim dv As New DataView(dt)
Return dv
End Function 'CreateDataSource
Sub Page_Load(sender As Object, e As EventArgs)
If CheckBox1.Checked Then
ItemsGrid.PagerStyle.Mode = PagerMode.NumericPages
Else
ItemsGrid.PagerStyle.Mode = PagerMode.NextPrev
End If
If Not IsPostBack Then
start_index = 0
ItemsGrid.VirtualItemCount = 100
End If
BindGrid()
End Sub 'Page_Load
Sub Grid_Change(sender As Object, e As DataGridPageChangedEventArgs)
ItemsGrid.CurrentPageIndex = e.NewPageIndex
start_index = ItemsGrid.CurrentPageIndex * ItemsGrid.PageSize
BindGrid()
End Sub 'Grid_Change
Sub BindGrid()
ItemsGrid.DataSource = CreateDataSource()
ItemsGrid.DataBind()
End Sub 'BindGrid
</script>
<body>
<form runat=server>
<h3>DataGrid Custom Paging Example</h3>
<asp:DataGrid id="ItemsGrid" runat="server"
BorderColor="black"
BorderWidth="1"
CellPadding="3"
AllowPaging="true"
AllowCustomPaging="true"
AutoGenerateColumns="false"
OnPageIndexChanged="Grid_Change">
<PagerStyle NextPageText="Forward"
PrevPageText="Back"
Position="Bottom"
PageButtonCount="5"
BackColor="#00aaaa">
</PagerStyle>
<AlternatingItemStyle BackColor="yellow">
</AlternatingItemStyle>
<HeaderStyle BackColor="#00aaaa">
</HeaderStyle>
<Columns>
<asp:BoundColumn HeaderText="Number"
DataField="IntegerValue"/>
<asp:BoundColumn
HeaderText="Item"
DataField="StringValue"/>
<asp:BoundColumn
HeaderText="Price"
DataField="CurrencyValue"
DataFormatString="{0:c}">
<ItemStyle HorizontalAlign="right">
</ItemStyle>
</asp:BoundColumn>
</Columns>
</asp:DataGrid>
<br>
<asp:CheckBox id="CheckBox1"
Text = "Show page navigation"
AutoPostBack="true"
runat="server"/>
</form>
</body>
</html>
<html>
<script language="VB" runat="server">
Dim start_index As Integer
Function CreateDataSource() As ICollection
Dim dt As New DataTable()
Dim dr As DataRow
dt.Columns.Add(New DataColumn("IntegerValue", GetType(Int32)))
dt.Columns.Add(New DataColumn("StringValue", GetType(String)))
dt.Columns.Add(New DataColumn("CurrencyValue", GetType(Double)))
Dim i As Integer
For i = start_index To (start_index + ItemsGrid.PageSize) - 1
dr = dt.NewRow()
dr(0) = i
dr(1) = "Item " + i.ToString()
dr(2) = 1.23 *(i + 1)
dt.Rows.Add(dr)
Next i
Dim dv As New DataView(dt)
Return dv
End Function 'CreateDataSource
Sub Page_Load(sender As Object, e As EventArgs)
If CheckBox1.Checked Then
ItemsGrid.PagerStyle.Mode = PagerMode.NumericPages
Else
ItemsGrid.PagerStyle.Mode = PagerMode.NextPrev
End If
If Not IsPostBack Then
start_index = 0
ItemsGrid.VirtualItemCount = 100
End If
BindGrid()
End Sub 'Page_Load
Sub Grid_Change(sender As Object, e As DataGridPageChangedEventArgs)
ItemsGrid.CurrentPageIndex = e.NewPageIndex
start_index = ItemsGrid.CurrentPageIndex * ItemsGrid.PageSize
BindGrid()
End Sub 'Grid_Change
Sub BindGrid()
ItemsGrid.DataSource = CreateDataSource()
ItemsGrid.DataBind()
End Sub 'BindGrid
</script>
<body>
<form runat=server>
<h3>DataGrid Custom Paging Example</h3>
<asp:DataGrid id="ItemsGrid" runat="server"
BorderColor="black"
BorderWidth="1"
CellPadding="3"
AllowPaging="true"
AllowCustomPaging="true"
AutoGenerateColumns="false"
OnPageIndexChanged="Grid_Change">
<PagerStyle NextPageText="Forward"
PrevPageText="Back"
Position="Bottom"
PageButtonCount="5"
BackColor="#00aaaa">
</PagerStyle>
<AlternatingItemStyle BackColor="yellow">
</AlternatingItemStyle>
<HeaderStyle BackColor="#00aaaa">
</HeaderStyle>
<Columns>
<asp:BoundColumn HeaderText="Number"
DataField="IntegerValue"/>
<asp:BoundColumn
HeaderText="Item"
DataField="StringValue"/>
<asp:BoundColumn
HeaderText="Price"
DataField="CurrencyValue"
DataFormatString="{0:c}">
<ItemStyle HorizontalAlign="right">
</ItemStyle>
</asp:BoundColumn>
</Columns>
</asp:DataGrid>
<br>
<asp:CheckBox id="CheckBox1"
Text = "Show page navigation"
AutoPostBack="true"
runat="server"/>
</form>
</body>
</html>
以上程序运行效果如下:
总结:
一般情况下,我们直接使用第一种方法进行数据分页,数据量较多或者对资源消耗比较敏感的话,使用第二种方法较好。