今天我要说的就是基于Oracle存储过程的一种简单的分页方式,首先就是页面前端发起对分页的请求,然后向Oracle存储过程中传入页面当前数,页面大小,查询的SQL语句,而存储过程返回来的则是数据总条数和当前页面要显示的数据集合。形式如下所示:
procedure P_GetPageSize(p_pagesize int,
p_startsize int,
p_sqlQuery varchar2,
out_pagecount out int,
out_datacollection out outData);
其中p_pagesize则是传入的每页显示的条数,p_startsize则是传入的页面索引,p_sqlQuery则是传入的SQL语句,out_pagecount则是返回的总记录条数,out_datacollection则是返回的数据集合。
上面就是分页存储过程的定义,在Oracle中,我写成了包,具体代码如下:
is
type outData is ref cursor ;
procedure P_GetPageSize(p_pagesize int ,
p_startsize int ,
p_sqlQuery varchar2 ,
out_pagecount out int ,
out_datacollection out outData);
end P_GetPageSize_pak;
create or replace package body scott.P_GetPageSize_pak
is
procedure P_GetPageSize(p_pagesize int ,
p_startsize int ,
p_sqlQuery varchar2 ,
out_pagecount out int ,
out_datacollection out outData)
as
v_sql varchar2 ( 3000 );
v_count int ;
v_upCount int ;
v_lowCount int ;
begin
-- 获取页面总的记录数
execute immediate ' select count(*) from ( ' || p_sqlQuery || ' ) ' into v_count;
out_pagecount: = v_count;
-- 获取数据的上下限
v_upCount: = p_startsize * p_pagesize; -- 上限
v_lowCount: = v_upCount - p_pagesize + 1 ; -- 下限
v_sql: = ' select * from (select a.*,rownum r from ( ' || p_sqlQuery || ' ) a where rownum <= ' || to_char(v_upCount) || ' ) B
where r>= ' || to_char(v_lowCount);
open out_datacollection for v_sql;
end P_GetPageSize;
end P_GetPageSize_pak;
上面的流程就是先获取页面的记录总数,然后利用select into 将其写入到out_pagecount变量中。然后再根据当前页面索引和每页显示的记录条数来得到需要返回的开始和截止记录条数。
最后返回数据集即可。
存储过程暂时在此打住,现在主要就是页面的处理了。
在asp.net页面中,处理Oracle中的包,就是利用形如“包头.存储过程名称(参数)“的方式引用即可。
具体代码示例如下(类Pagination.cs):
using System.Collections.Generic;
using System.Web;
using System.Data;
using System.Data.OracleClient;
using System.Configuration;
/// <summary>
/// Pagination 的摘要说明
/// </summary>
public class Pagination
{
public Pagination() { }
public static string connStr = ConfigurationManager.ConnectionStrings[ " Oracle-MS " ].ToString();
public static OracleConnection CreateConn()
{
OracleConnection conn = new OracleConnection(connStr);
conn.Open();
return conn;
}
public static DataSet PaginationPager( string sqlQuery, int _pageSize, int _startsize, out int _sqlCount)
{
DataSet ds = new DataSet();
using (OracleConnection conn = CreateConn())
{
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = " P_GetPageSize_pak.P_GetPageSize " ;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add( " p_pagesize " , OracleType.Int32);
cmd.Parameters[ " p_pagesize " ].Direction = ParameterDirection.Input;
cmd.Parameters[ " p_pagesize " ].Value = _pageSize;
cmd.Parameters.Add( " p_startsize " , OracleType.Int32);
cmd.Parameters[ " p_startsize " ].Direction = ParameterDirection.Input;
cmd.Parameters[ " p_startsize " ].Value = _startsize;
cmd.Parameters.Add( " p_sqlQuery " , OracleType.VarChar);
cmd.Parameters[ " p_sqlQuery " ].Direction = ParameterDirection.Input;
cmd.Parameters[ " p_sqlQuery " ].Value = sqlQuery;
cmd.Parameters.Add( " out_pagecount " , OracleType.Int32);
cmd.Parameters[ " out_pagecount " ].Direction = ParameterDirection.Output;
cmd.Parameters.Add( " out_datacollection " , OracleType.Cursor);
cmd.Parameters[ " out_datacollection " ].Direction = ParameterDirection.Output;
OracleDataAdapter oda = new OracleDataAdapter(cmd);
oda.Fill(ds);
_sqlCount = Int32.Parse(cmd.Parameters[ " out_pagecount " ].Value.ToString()); // 这句一定要放到fill方法后
return ds;
}
}
上面的流程主要就是先打开Oracle数据库,然后将参数传入,最后将查询得到的数据总条数通过out参数进行值的保留,在被引用的时候,给引用传递过去;将数据集合填充到DataSet中给返回回去。
那么在页面中,如何使用分页类呢?
要实现分页,首先得拖入四个按钮,分别为“首页“、”上一页“、”下一页“、”尾页“,然后写入响应的响应事件函数即可。
需要注意的是,这里一定要正确的判断页尾和页首,然后只要数据到达页首,“首页“按钮和”上一页“按钮使能失效,而数据叨叨页尾,”下一页“、”尾页“使能失效。
具体请看页面代码:
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
public partial class _Default : System.Web.UI.Page
{
public static int _pageSize = 10 ;
public static int _startSize = 1 ;
public static int totalCount;
protected void Page_Load( object sender, EventArgs e)
{
if ( ! IsPostBack)
{
Bind();
}
}
private void Bind()
{
string sqlQuery = " select nsrsbm,nsr_mc,djlx_mc,dj_ztmc,zclx_mc,gljg_mc,zgy_mc,ssx_mc from scott.t_yhs_djxxtz " ;
DataSet ds = Pagination.PaginationPager(sqlQuery, _pageSize, _startSize, out totalCount);
GridView1.DataSource = ds.Tables[ " Table " ] ;
GridView1.DataBind();
if (_startSize <= 1 ) // 如果当前为第一页
{
if (_startSize * _pageSize >= totalCount) // 如果当前总条数小于一页的条数 那么按钮全部为不可用状态
{
lbtnFirst.Enabled = false ;
lbtnPrev.Enabled = false ;
lbtnNext.Enabled = false ;
lbtnEnd.Enabled = false ;
}
else // 如果当前总条数大于一页的条数,那么首页 上一页 不可用,下一页 末页 可用
{
lbtnFirst.Enabled = false ;
lbtnPrev.Enabled = false ;
lbtnNext.Enabled = true ;
lbtnEnd.Enabled = true ;
}
}
else // 如果当前页数不是第一页
{
if ((totalCount - _startSize * _pageSize) / _pageSize == 0 ) // 表明到达了最后一页
{
lbtnFirst.Enabled = true ;
lbtnPrev.Enabled = true ;
lbtnNext.Enabled = false ;
lbtnEnd.Enabled = false ;
}
else
{
lbtnFirst.Enabled = true ;
lbtnPrev.Enabled = true ;
lbtnNext.Enabled = true ;
lbtnEnd.Enabled = true ;
}
}
int pageCount = ((totalCount % _pageSize) == 0 ) ? (totalCount / _pageSize) : ((totalCount / _pageSize) + 1 );
lblInfo.Text = " 当前第 " + _startSize + " 页,总共 " + pageCount + " 页 " ;
}
protected void lbtnFirst_Click( object sender, EventArgs e)
{
int pageCount = ((totalCount % _pageSize) == 0 ) ? (totalCount / _pageSize) : ((totalCount / _pageSize) + 1 );
_startSize = 1 ;
Bind();
lblInfo.Text = " 当前第 " + _startSize + " 页,总共 " + pageCount + " 页 " ;
}
protected void lbtnPrev_Click( object sender, EventArgs e)
{
int pageCount = ((totalCount % _pageSize) == 0 ) ? (totalCount / _pageSize) : ((totalCount / _pageSize) + 1 );
if (_startSize > 1 )
{
_startSize = _startSize - 1 ;
Bind();
}
lblInfo.Text = " 当前第 " + _startSize + " 页,总共 " + pageCount + " 页 " ;
}
protected void lbtnNext_Click( object sender, EventArgs e)
{
int pageCount = ((totalCount % _pageSize) == 0 ) ? (totalCount / _pageSize):((totalCount / _pageSize) + 1 );
if (_startSize < pageCount)
{
_startSize = _startSize + 1 ;
Bind();
}
lblInfo.Text = " 当前第 " + _startSize + " 页,总共 " + pageCount + " 页 " ;
}
protected void lbtnEnd_Click( object sender, EventArgs e)
{
int pageCount = ((totalCount % _pageSize) == 0 ) ? (totalCount / _pageSize):((totalCount / _pageSize) + 1 );
_startSize = pageCount;
Bind();
lblInfo.Text = " 当前第 " + _startSize + " 页,总共 " + pageCount + " 页 " ;
}
}
在asp.net前端的代码如下:
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title > 测试Oracle的分页存储过程 </ title >
< link href ="css/TableZB.css" rel ="stylesheet" type ="text/css" />
< link href ="css/swcss.css" rel ="stylesheet" type ="text/css" />
< link href ="css/GridViewCSS_O.css" rel ="stylesheet" type ="text/css" />
< style type ="text/css" >
.Pager
{
margin : 5px ;
text-align : right ;
}
.Pager a
{
color : Red ;
}
.Pager a:hover
{
color : Blue ;
}
.Pager a:visited
{
text-decoration : none ;
font-size : 12px ;
color : Red ;
}
</ style >
</ head >
< body >
< form id ="form1" runat ="server" style ="width: 100%" >
< asp:GridView CssClass ="GVtable" ID ="GridView1" runat ="server" Width ="100%" AutoGenerateColumns ="False" >
< Columns >
< asp:TemplateField HeaderText ="纳税人识别码" >
< ItemTemplate > <% # Eval ( " nsrsbm " ).ToString() %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="纳税人名称" >
< ItemTemplate > <% # Eval ( " nsr_mc " ) %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="登记类型" >
< ItemTemplate > <% # Eval ( " djlx_mc " ) %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="登记状态" >
< ItemTemplate > <% # Eval ( " dj_ztmc " ) %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="注册类型" >
< ItemTemplate > <% # Eval ( " zclx_mc " ) %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="所别" >
< ItemTemplate > <% # Eval ( " gljg_mc " ) %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="专管员" >
< ItemTemplate > <% # Eval ( " zgy_mc " ) %> </ ItemTemplate >
</ asp:TemplateField >
< asp:TemplateField HeaderText ="所属性"
< ItemTemplate > <% # Eval ( " ssx_mc " ) %> </ ItemTemplate >
</ asp:TemplateField >
</ Columns >
</ asp:GridView >
< div class ="Pager" >
< asp:LinkButton ID ="lbtnFirst" runat ="server" onclick ="lbtnFirst_Click" > 首页 </ asp:LinkButton >
< asp:LinkButton ID ="lbtnPrev" runat ="server" onclick ="lbtnPrev_Click" > 上一页 </ asp:LinkButton >
< asp:LinkButton ID ="lbtnNext" runat ="server" onclick ="lbtnNext_Click" > 下一页 </ asp:LinkButton >
< asp:LinkButton ID ="lbtnEnd" runat ="server" onclick ="lbtnEnd_Click" > 末页 </ asp:LinkButton >
< asp:Label ID ="lblInfo" runat ="server" Text ="" ></ asp:Label >
</ div >
</ form >
</ body >
</ html >
好了 具体的页面效果请看下图:
到这里就完成了,不过,很不完美,如果项目中好多地方要引用这个存储过程分页的话, 那不是每次都要拖入控件,然后写一大堆代码吗?这样不累死人吗?
呵呵 ,当然不是的,下节就讲如何将分页函数封装到web用户控件上,然后用户直接调用即可。