GridView,ASP.NET中的表格控件,和Repeater控件一样,在ASP.NET中都是很常用的两个表格控件,GridView自己也有分页功能,实现是将一张表的数据全部绑定到GridView,然后再进行分页,这就是通常我们所说的‘假分页‘。在应对小数据量上完全没问题,但问题往往没有那么简单,在面对大数据量的问题上,GridView自己的分页还是力不从心,严重影响效率,用户体验也不好。
要解决这个问题,实现‘真分页‘,就要从根上去分析,为什么‘假分页‘速度慢,因为它一次获取的是整张表的数据,但是最后显示的只是一页,所以,如果我们只查询需要显示的一页数据(上页下页,首页尾页,跳页都只查询需要的一页数据),在绑定到GridView中,查询分页的速度会快很多,这就是所谓的‘真分页‘了。剩下的问题就是SQL语句去实现了。经过一番查询研究,通过存储过程实现真分页效果挺好。
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[PROC_GridViewPage] --@TableList Varchar(200), --查询的字段,用逗号隔开 @TableName Varchar(30), --查询的表名 --@SelectWhere Varchar(500),--查询的条件 @SelectOrderId Varchar(20), --表主键字段名 @SelectOrder Varchar(200), --排序,order by 列名 @intPageNo int, --页号 @intPageSize int, --每页显示数 @RecordCount int OUTPUT --总记录数(OUTPUT表示是存储过程输出型参数,接收方法见DAL层) AS declare @TmpSelect NVarchar(600) --声明变量 set nocount on --关闭计数 --获取表中记录总数 set @TmpSelect = ‘select @RecordCount = count(*) from ‘+@TableName+‘ ‘ --可以添加查询条件+@SelectWhere execute sp_executesql @TmpSelect, --执行上面的sql语句 N‘@RecordCount int OUTPUT‘ , --执行输出数据的sql语句,output出总记录数 @RecordCount OUTPUT if (@RecordCount = 0) --如果表中没有,则返回0 return 0 /*判断页数是否正确*/ if (@intPageNo - 1) * @intPageSize > @RecordCount --页号大于总页数,返回错误 return (-1) set nocount off--打开计数 BEGIN set @TmpSelect = ‘select top ‘+str(@intPageSize)+‘ ‘+ ‘*‘ +‘ from ‘+@TableName+‘ where ‘+@SelectOrderId+‘ not in(select top ‘+str((@intPageNo-1)*@intPageSize)+‘ ‘+@SelectOrderId+‘ from ‘+@TableName+‘ ‘+@SelectOrder+‘) ‘+@SelectOrder END execute sp_executesql @TmpSelect return(@@rowcount) GO
sp_executesql?和EXEC一样在存储过程中执行sql语句的命令,平时我们见到和使用的通常是EXEC,sp_executesql的不同之出在于,它提供了一个借口,支持参数的输入和输出,灵活性更好,而且sp_executesql的执行性能更好。还没有深入研究sp_executesql,既然都说比EXEC好,那就先用吧。
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="List.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>GridView分页</title> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView ID="gridView" runat="server" AllowPaging="True" Width="100%" CellPadding="3" OnPageIndexChanging="gridView_PageIndexChanging" BorderWidth="1px" DataKeyNames="ID" OnRowDataBound="gridView_RowDataBound" AutoGenerateColumns="false" RowStyle-HorizontalAlign="Center" OnRowCreated="gridView_OnRowCreated" EmptyDataText="没有您查找的数据" ShowHeaderWhenEmpty="True" PageSize="20" > <Columns> <asp:BoundField DataField="name" HeaderText="姓名" SortExpression="name" ItemStyle-HorizontalAlign="Center"> <asp:BoundField DataField="sex" HeaderText="性别" SortExpression="sex" ItemStyle-HorizontalAlign="Center"> </asp:BoundField> <asp:BoundField DataField="idNumber" HeaderText="身份证号" SortExpression="idNumber" ItemStyle-HorizontalAlign="Center"> </asp:BoundField> </Columns> </asp:GridView> </div> <asp:HyperLink ID="pagefirst" runat="server">首页</asp:HyperLink> <asp:HyperLink ID="pageup" runat="server">上一页</asp:HyperLink> <asp:HyperLink ID="pagedown" runat="server">下一页</asp:HyperLink> <asp:HyperLink ID="pageend" runat="server">尾页</asp:HyperLink> 第<asp:Label ID="lbRow" runat="server" Text="Label"></asp:Label>页, 共<asp:Label ID="lbpage" runat="server" Text="Label"></asp:Label>页, 共<asp:Label ID="lbRecord" runat="server" Text="Label"></asp:Label>条记录, 转到<asp:TextBox ID="txtlink" runat="server" Width="29px"></asp:TextBox>页 <asp:LinkButton ID="link" runat="server" OnClick="link_Click" TabIndex="1">转到</asp:LinkButton> </form> </body> </html>
这个实体类的作用是定义了存储过程中的变量:字段,表名,查询条件,主键,排序方式,页号,总记录数
public partial class GridViewPageEntity { public GridViewPageEntity() {} ///定义属性中的变量 /// <summary> /// 字段,表名,查询条件,主键,排序方式,页号,总记录数 /// </summary> private string _Fields; private string _TableName; private string _SelectWhere; private string _Primarykey; private string _OrderBy; private int _intPageNo; private int _intPageSize; private int _RecordCount; //属性 public string Fields { set { _Fields = value; } get { return _Fields; } } public string TableName { set { _TableName = value; } get { return _TableName; } } public string SelectWhere { set { _SelectWhere = value; } get { return _SelectWhere; } } public string Primarykey { set { _Primarykey = value; } get { return _Primarykey; } } public string OrderBy { set { _OrderBy = value; } get { return _OrderBy; } } public int intPageNo { set { _intPageNo = value; } get { return _intPageNo; } } public int intPageSize { set { _intPageSize = value; } get { return _intPageSize; } } public int RecordCount { set { _RecordCount = value; } get { return _RecordCount; } } }
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) //判断是否第一次加载页面 { BindData(); } } #region 数据绑定 public void BindData() { private readonly GridViewPageBLL gridViewPageBll = new GridViewPageBLL(); //实例化GridViewPageBLL 业务逻辑类 PersonalFiles.Entity.GridViewPageEntity gridViewEntity = new Entity.GridViewPageEntity();//实例化GridViewPageEntity实体类 gridViewEntity.intPageNo = 1; //起始页号 gridViewEntity.intPageSize = 20; //每页显示行数 gridViewEntity.TableName = "V_XINMainTecnce"; //查询的表名(这里用的视图) gridViewEntity.Primarykey = "pri"; //主键 gridViewEntity.OrderBy = "order by ID"; //排序方式 //获取当前页号,判断是否获取页,没有则页号为起始页 if (Request.QueryString["CurrentPage"] == null) { gridViewEntity.intPageNo = 1; } else { gridViewEntity.intPageNo = Int32.Parse(Request.QueryString["CurrentPage"]); } int sumPage; //定义总页数 int pageNo = gridViewEntity.intPageNo; //当前页数 int pageSize = gridViewEntity.intPageSize; //每页显示行数 DataTable dt = new DataTable(); //实例化DataTable dt = gridViewPageBll.GetList(gridViewEntity); //获取数据列表 gridView.DataSource = dt; //绑定数据 gridView.DataBind(); string allcount = dt.Rows[0]["allcount"].ToString(); //获取表中数据总行数 Int32 RecordCount = int.Parse(allcount); //求出总记录数,该值是output出来的值 Int32 RowCount = (Int32)dt.Rows.Count; //求出当前页中的记录数,在最后一页不等于pagesize, lbRecord.Text = RecordCount.ToString(); //显示总条数 lbRow.Text = pageNo.ToString(); //显示当前页数 sumPage = (Int32)RecordCount / pageSize; //计算总页数 if (RecordCount % pageSize > 0) //判断总行数是否大于每页行数,是则总页数自加1 { sumPage = sumPage + 1; } lbpage.Text = sumPage.ToString(); //显示总页数 if (pageNo > 1) //判断当前页是否大于1(不是首页),判断是否可以进行首页和上一页 { pagefirst.NavigateUrl ="List.aspx?CurrentPage=1"; //链接首页 pageup.NavigateUrl =string.Concat("List.aspx?CurrentPage=", "", pageNo - 1); //上一页操作 } else { pageup.NavigateUrl =""; pagefirst.NavigateUrl =""; } if (pageNo < sumPage) //判断当前页是否小于总页数,判断是否可以进行下一页和最后一页 { pageend.NavigateUrl =string.Concat("List.aspx?CurrentPage=", "", sumPage); //最后一页操作 pagenext.NavigateUrl =string.Concat("List.aspx?CurrentPage=", "", pageNo + 1); //下一页操作 } else { pagenext.NavigateUrl =""; pageend.NavigateUrl =""; } } #endregion
/// <summary> /// GridView分页 逻辑类 /// </summary> public partial class GridViewPageBLL { private readonly MainTenanceDAL gridViewPageDal=new GridViewPageDAL(); /// <summary> /// 获取数据BLL方法 /// </summary> /// <param name="gridViewEntity">分页参数实体</param> /// <returns>返回DataTable</returns> public DataTable GetList(PersonalFiles.Entity.GridViewPageEntity gridViewEntity) { return gridViewPageDal.GetList(gridViewEntity); } }
/// <summary> /// 查询数据DAL方法 /// </summary> /// <param name="gridViewEntity"></param> /// <returns></returns> public DataTable GetList(PersonalFiles.Entity.GridViewPageEntity gridViewEntity) { //存储过程 string strSql = "PROC_GridViewPage"; //添加赋值参数 SqlParameter[] paras = new SqlParameter[] { //new SqlParameter("@TableList","ID"), new SqlParameter("@TableName",gridViewEntity.TableName), new SqlParameter ("@SelectOrderId",gridViewEntity.Primarykey), new SqlParameter ("@SelectOrder",gridViewEntity.OrderBy), new SqlParameter ("@intPageNo",gridViewEntity.intPageNo), new SqlParameter ("@intPageSize",gridViewEntity.intPageSize), new SqlParameter ("@RecordCount",SqlDbType.Int), new SqlParameter ("RowCount", SqlDbType.Int) }; //获取表中总数据量,如果不需要界面显示可以不用获取。 paras[5].Direction = ParameterDirection.Output; //获取查询的一页的数据量,我们在界面层给@intPageSize赋的值是20,所以这里返回来的也是20 paras[6].Direction = ParameterDirection.ReturnValue; DataSet ds = new DataSet(); //执行带参数的查询存储过程 DataTable dt = DbHelperSQL.ExecuteQuery(strSql,paras,CommandType.StoredProcedure); string allcount = paras[5].Value.ToString(); string count = paras[6].Value.ToString(); //存储表总数据量,如果不需要界面显示可以不用获取。 dt.Columns.Add("allcount", typeof(string)); dt.Rows[0]["allcount"] = allcount; //返回查询结果(datatable) return dt; }
SqlParameter类的属性Direction作用在获取或者设置一个值,该值指示参数是只可以输入,只可以输出,双向,还是存储过程返回值参数。
paras[5].Direction= ParameterDirection.Output;得到存储过程执行后的输出值
paras[6].Direction= ParameterDirection.ReturnValue;得到存储过程执行后的返回值
要实现这个获取值需要在存储过程中将参数设为OUTPUT类型:@RecordCount int OUTPUT,详看存储过程。
代码实现完成了,整个过程很清楚了,不过感觉还有很多不太明白的地方,可能就是对其中的细节上理解的不太明白,也是以前没有接触过不熟悉的原因吧。不纠结了,最后能够从全局上掌握这个方法,会用了即可吧。
学习牛腩的时候用过第三方控件AspNetPager,只要引入封装的.dll就能实现真分页,原理上应该是一样的,而且它都给你封装好了,拿来用就行,怎么封装出来的,看来还要好好研究。
GridView+存储过程实现'真分页',布布扣,bubuko.com
原文:http://blog.csdn.net/akkzhjj/article/details/21285183