再上数据分页控件(不用存储过程)
发布日期:2011年04月04日 星期一 作者:EricHu
本篇主要内容如下:
· 概述
· 本分页控件原理。
· 分页控件代码。
· 分页控件使用实例。
概述
在前几篇:我介绍了原创企业级控件库之大数据据量分页控件,这个控件主要是通过存储过程进行数据分页,得到了大家的支持,也给出了许多宝贵的建议,在这儿先感谢各位。同时也让我更有信心进行以后的文章(企业级控件库系列)。
分页对于每个项目来说都有它存在的意义,想起在以前刚刚刚软件开发时,由于刚刚毕业,理论知识雄厚,但实际工作经验欠缺,记得几年前做开发时,数据量很大,要用分页,一开始真不知道如何是好,方法到知道,但速度与稳定性却没有经验。在这儿,我只是起到一个抛砖引玉的作用,以便引起我们在实际工作中要多思考,对同一件事多想几种解决方式,只有这样才能不断提高,同时要学会总结。
这篇我将给大家介绍:不用存储过程,直接用代码来实现数据分页,欢迎大家拍砖,觉得不错的可以推荐下。同时,你要用什么好的想法,也可以与我交流,谢谢。
本分页控件原理
分页的方法很多,有用存储过程的,有不用存储过程的,还有在C#中用DataGridView的虚拟模式的,目的只有一个,对大数据量进行处理,让用户体验得到提高,软件速度得到提升。本分页控件主要是用了下面的SQL语句,我相信你能看懂的,存储过程分页也是用类似的SQL代码:
2 SqlWhereStatement :Sql Where表达式 如:where表达式为空
3 PrimaryKey :主键 如:UniqueID
4 PageSize :分页大小 如:50
5 pageIndex :当前页 如:8
6 OrderField :排序字段 如:InsetDataTime
7 */
8
9 SELECT TOP 50 * FROM tbTestData
10 WHERE UniqueID >
11 (
12 SELECT ISNULL(MAX(id),0) FROM
13 )
14 ORDER BY UniqueID
原理就这么简单。
分页控件代码
(一)、实例数据库代码
创建实例数据库。
[UniqueID] [bigint] NOT NULL,
[CompanyName] [varchar](200) NULL,
[CompanyCode] [varchar](50) NULL,
[Address] [varchar](500) NULL,
[Owner] [varchar](100) NULL,
[Memo] [varchar](2000) NULL,
[InsetDataTime] [datetime] NULL,
CONSTRAINT [PK_tbTestData] PRIMARY KEY CLUSTERED
(
[UniqueID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tbTestData] ADD CONSTRAINT [DF_tbTestData_InsetDataTime] DEFAULT (getdate()) FOR [InsetDataTime]
GO
--生成实例数据
declare @intRowNumber int;
select @intRowNumber = 1;
while @intRowNumber < 1000000
begin
insert into tbTestData(UniqueID,CompanyName,CompanyCode,Address,Owner,Memo)
values(@intRowNumber,'CompanyName' + cast(@intRowNumber as varchar(2000)),
'CompanyCode' + cast(@intRowNumber as varchar(2000)),'Address'+ cast(@intRowNumber as varchar(2000)),
'Owner' + cast(@intRowNumber as varchar(2000)),'Memo' + cast(@intRowNumber as varchar(2000)));
select @intRowNumber = @intRowNumber + 1
end
(二)、分页控件代码。
{
/// <summary>
/// 分页控件(使用代码实现,不用存储过程)
/// UcPageControlByCode
/// 修改纪录
///
/// 2010-01-06 胡勇 修改转到某页由原来的KeyPress方法改为KeyDown,让用户按回车键确认转页,以防止连续绑定两次。
/// 2011-01-06 胡勇 增加对分页控件的初始化代码:public DataTable InitializePageControl()。
/// 2011-01-05 胡勇 创建分页控件
/// 2011-04-02 胡勇 优化代码、减少不必要的私有变量,去掉多余的代码
///
/// <author>
/// <name>胡勇</name>
/// <QQ>80368704</QQ>
/// <Email>80368704@qq.com</Email>
/// </author>
/// </summary>
[ToolboxItem(true)]
[DefaultEvent("OnEventPageClicked")]
[ToolboxBitmap(typeof(UcPageControlByCode), "Images.UcPageControlByCodeIcon.png")]
[Description("分页控件(使用代码实现,不用存储过程)")]
public partial class UcPageControlByCode : UserControl
{
#region 私有变量
int recordCount = 0; //记录数
int pageCount = 0; //总页数
int pageIndex = 0; //当前页
#endregion
#region 自定义事件
/// <summary>
/// 单击分页按钮(第一页、上一页、下一页、最后页、跳页)时发生
/// </summary>
[Category("UcPageControlByCode"), Description("单击分页按钮时发生")]
public event EventHandler OnEventPageClicked;
#endregion
#region 自定义属性
private int _pageSize = 50; //分页大小
private string _sqlWhereStatement = string.Empty; //MsSql Where语句
private string _sqlConnString = string.Empty; //MsSql 数据库连接字符串
private string _tableName = string.Empty; //表名
private string _orderField = string.Empty; //数据表的排序字段
private string _primaryKey = string.Empty; //数据表的主键
private string _queryFieldList = "*"; //字段列表(默认为:*)
private DataTable _pageTable = new DataTable();
/// <summary>
/// 返回当前页码
/// </summary>
public int PageIndex
{
get
{
return pageIndex + 1;
}
}
/// <summary>
/// 得到或设置分页大小(默认为:50)
/// </summary>
[Browsable(true), Category("UcPageControlByCode"), Description("得到或设置分页大小(默认为:50)")]
public int PageSize
{
get
{
return _pageSize;
}
set
{
_pageSize = value;
}
}
/// <summary>
/// SQL语句的Where表达式
/// </summary>
[Browsable(false), Category("UcPageControlByCode"), Description("得到或设置SQL语句的Where表达式")]
public string SqlWhereStatement
{
get
{
return _sqlWhereStatement;
}
set
{
_sqlWhereStatement = value;
}
}
/// <summary>
/// 得到或设置SqlServer的连接字符串
/// </summary>
[Browsable(false), Category("UcPageControlByCode"), Description("得到或设置SqlServer的连接字符串")]
public string SqlConnString
{
get
{
return _sqlConnString;
}
set
{
_sqlConnString = value;
}
}
/// <summary>
/// 得到用户单击分页按钮后返回的DataTable
/// </summary>
[Browsable(false), Category("UcPageControlByCode"), Description("得到用户单击分页按钮后返回的DataTable")]
public DataTable PageTable
{
get
{
return _pageTable;
}
}
/// <summary>
/// 设置或得到与分页控件绑定的表名或视图名
/// </summary>
[Browsable(true), Category("UcPageControlByCode"), Description("设置或得到与分页控件绑定的表名或视图名")]
public string TableName
{
get
{
return _tableName;
}
set
{
_tableName = value;
}
}
/// <summary>
/// 设置或得到分页控件排序字段
/// </summary>
[Browsable(true), Category("UcPageControlByCode"), Description("设置或得到分页控件排序字段")]
public string OrderField
{
get
{
return _orderField;
}
set
{
_orderField = value;
}
}
/// <summary>
/// 设置或得到分页控件绑定数据表的主键
/// </summary>
[Browsable(true), Category("UcPageControlByCode"), Description("设置或得到分页控件绑定数据表的主键")]
public string PrimaryKey
{
get
{
return _primaryKey;
}
set
{
_primaryKey = value;
}
}
/// <summary>
/// 设置或得到分页控件绑定的字段列表(默认为:*)
/// </summary>
[Browsable(true), Category("UcPageControlByCode"), Description("设置或得到分页控件绑定的字段列表(默认为:*)")]
public string QueryFieldList
{
get
{
return _queryFieldList;
}
set
{
_queryFieldList = value;
}
}
#endregion
#region 构造函数
/// <summary>
/// 分页控件(使用代码实现,不用存储过程)
/// </summary>
public UcPageControlByCode()
{
InitializeComponent();
}
#endregion
#region 分页实现相关代码
#region void SetUcPageControlPars(string connStr, string whereStatement, string tbName, string orderField, string primaryKeyName, string fieldList):给UcPageControlByCode控件传递必需参数
/// <summary>
/// 给UcPageControlByCode控件传递必需参数
/// </summary>
/// <param name="connStr">连接字符串</param>
/// <param name="whereStatement">MsSql Where语句 </param>
/// <param name="tbName">数据表名或视力名</param>
/// <param name="orderField">排序字段</param>
/// <param name="primaryKeyName">主键值</param>
/// <param name="fieldList">字段列表(默认为:*)</param>
public void SetUcPageControlPars(string connStr, string whereStatement, string tbName
, string orderField, string primaryKeyName, string fieldList)
{
if (string.IsNullOrEmpty(connStr.Trim()))
{
DialogHelper.ShowErrorMsg("温馨提示:\n无可用的数据库连接!");
return;
}
else
{
this.SqlConnString = connStr;
}
this.SqlWhereStatement = whereStatement;
this.TableName = tbName;
this.OrderField = orderField;
this.PrimaryKey = primaryKeyName;
if (!string.IsNullOrEmpty(fieldList.Trim()))
{
this.QueryFieldList = fieldList;
}
}
#endregion
#region DataTable InitializePageControl():初始化UcPageControlByCode
/// <summary>
/// 绑定UcPageControlByCode(并返回包含当前页的DataTable)
/// </summary>
/// <returns>DataTable</returns>
public DataTable BindPageControl()
{
recordCount = GetTotalRecordCount(); //获取总记录数
pageCount = recordCount / PageSize - ModPage(); //保存总页数(减去ModPage()函数防止SQL语句执行时溢出查询范围,可以用存储过程分页算法来理解这句)
pageIndex = 0; //保存一个为0的页面索引值到pageIndex
lblPageCount.Text = (recordCount / PageSize + OverPage()).ToString();//显示lblpageCount、lblrecCount的状态
lblRecCount.Text = recordCount.ToString();
if (recordCount <= PageSize)
{
txtGoToPage.Enabled = false;
}
else
{
txtGoToPage.Enabled = true;
}
return TDataBind();
}
#endregion
/// <summary>
/// 计算余页
/// </summary>
/// <returns></returns>
private int OverPage()
{
int returnValue = 0;
if (recordCount % PageSize != 0)
{
returnValue = 1;
}
return returnValue;
}
/// <summary>
/// 计算余页,防止SQL语句执行时溢出查询范围
/// </summary>
/// <returns></returns>
private int ModPage()
{
int returnValue = 0;
if (recordCount % PageSize == 0 && recordCount != 0)
{
returnValue = 1;
}
return returnValue;
}
/// <summary>
/// 计算总记录数
/// </summary>
/// <returns>记录总数</returns>
private int GetTotalRecordCount()
{
int returnValue = 0;
string sqlStatement = "select count(1) as rowsCount from " + TableName;
if (SqlWhereStatement.Trim().Length > 0)
{
sqlStatement = "select count(1) as rowsCount from " + TableName + " where " + SqlWhereStatement;
}
SqlDataReader dr = null;
try
{
dr = DbHelperSQL.ExecuteReader(sqlStatement, SqlConnString);
if (dr.Read())
{
returnValue = Int32.Parse(dr["rowsCount"].ToString());
}
}
catch(Exception ex)
{
DialogHelper.ShowErrorMsg(ex.Message);
}
finally
{
dr.Close();
dr.Dispose();
}
return returnValue;
}
#endregion
#region DataTable TDataBind():数据绑定
private DataTable TDataBind()
{
StringBuilder sbSqlStatement = new StringBuilder();
bool isForward = pageIndex + 1 > 1;
bool isBackward = (pageIndex != pageCount);
btnFirstPage.Enabled = isForward;
btnPrevPage.Enabled = isForward;
btnNextPage.Enabled = isBackward;
btnLastPage.Enabled = isBackward;
if (string.IsNullOrEmpty(SqlWhereStatement.Trim()))
{
sbSqlStatement.Append("SELECT TOP " + PageSize + " " + QueryFieldList + " FROM " + TableName + " WHERE " + PrimaryKey + " NOT IN(SELECT TOP ");
sbSqlStatement.Append(PageSize * pageIndex + " " + PrimaryKey + " FROM " + TableName);
sbSqlStatement.Append(" ORDER BY " + OrderField +" DESC) ORDER BY " + OrderField + " DESC");
}
else
{
sbSqlStatement.Append("SELECT TOP " + PageSize + " " + QueryFieldList + " FROM " + TableName + " WHERE " + SqlWhereStatement + " AND " + PrimaryKey + " NOT IN(SELECT TOP ");
sbSqlStatement.Append(PageSize * pageIndex + " " + PrimaryKey + " FROM " + TableName + " WHERE " + SqlWhereStatement + " ORDER BY " + OrderField + " DESC) ORDER BY " + OrderField + " DESC");
}
_pageTable = DbHelperSQL.Query(sbSqlStatement.ToString(), SqlConnString).Tables[0];
lblCurrentPage.Text = (pageIndex + 1).ToString();
txtGoToPage.Text = (pageIndex + 1).ToString();
return _pageTable;
}
#endregion
#region 按钮事件代码
private void btnFirstPage_Click(object sender, EventArgs e)
{
pageIndex = 0;
_pageTable = TDataBind();
if (OnEventPageClicked != null)
{
OnEventPageClicked(this, null);
}
}
private void btnPrevPage_Click(object sender, EventArgs e)
{
pageIndex--;
_pageTable = TDataBind();
if (OnEventPageClicked != null)
{
OnEventPageClicked(this, null);
}
}
private void btnNextPage_Click(object sender, EventArgs e)
{
pageIndex++;
_pageTable = TDataBind();
if (OnEventPageClicked != null)
{
OnEventPageClicked(this, null);
}
}
private void btnLastPage_Click(object sender, EventArgs e)
{
pageIndex = pageCount;
_pageTable = TDataBind();
if (OnEventPageClicked != null)
{
OnEventPageClicked(this, null);
}
}
private void txtGoToPage_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
try
{
if (Int32.Parse(txtGoToPage.Text) > (recordCount / PageSize + OverPage()) || Int32.Parse(txtGoToPage.Text) <= 0)
{
DialogHelper.ShowWarningMsg("页码范围越界!");
txtGoToPage.Clear();
txtGoToPage.Focus();
}
else
{
pageIndex = Int32.Parse(txtGoToPage.Text.ToString()) - 1;
_pageTable = TDataBind();
if (OnEventPageClicked != null)
{
OnEventPageClicked(this, null);
}
}
}
catch (Exception ex) //捕获由用户输入不正确数据类型时造成的异常
{
DialogHelper.ShowWarningMsg(ex.Message);
txtGoToPage.Clear();
txtGoToPage.Focus();
}
}
}
#endregion
#endregion
}
}
分页控件使用实例
客户端使用代码如下:
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Configuration;
7 using DotNet.Controls;
8 using System.Text;
9 using System.Windows.Forms;
10 using DotNet.Common;
11 using DotNet.WinForm.Utilities;
12
13 namespace DotNet.WinForm.Example
14 {
15 public partial class FrmUcPageControlByCodeTest : Form
16 {
17 public FrmUcPageControlByCodeTest()
18 {
19 InitializeComponent();
20 }
21
22 private void FrmUcPageControlByCodeTest_Shown(object sender, EventArgs e)
23 {
24 //初始化方法一
25 //ucPageControlByCode.SqlConnString = ConfigurationSettings.AppSettings["DbConnection"];
26 //ucPageControlByCode.SqlWhereStatement = "1=1";
27 //ucPageControlByCode.TableName = "tbTestData";
28 //ucPageControlByCode.OrderField = "UniqueID";
29 //ucPageControlByCode.PrimaryKey = "UniqueID";
30 //ucPageControlByCode.QueryFieldList = "*";
31
32 //初始化方法二
33 ucPageControlByCode.SetUcPageControlPars(ConfigurationSettings.AppSettings["DbConnection"], "1=1", "tbTestData",
34 "UniqueID", "UniqueID", "*");
35 DataTable dtTest = new DataTable();
36 dtTest = ucPageControlByCode.BindPageControl();
37 ucDataGridView.DataSource = dtTest;
38
39 //绑定查询项
40 Dictionary<string, string> dicListQueryItems = new Dictionary<string, string>();
41 foreach (DataColumn dc in dtTest.Columns)
42 {
43 dicListQueryItems.Add(dc.ColumnName, dc.DataType.ToString());
44 }
45 ucCombinQuery1.SetQueryItems(dicListQueryItems);
46 }
47
48 private void ucDataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
49 {
50 gbMain.Text = "当前共:" + ucDataGridView.Rows.Count.ToString() + "条数据。";
51 }
52
53 private void ucPageControlByCode_OnEventPageClicked(object sender, EventArgs e)
54 {
55 ucDataGridView.DataSource = null;
56 ucDataGridView.DataSource = ucPageControlByCode.PageTable;
57 }
58
59 private void ucCombinQuery1_OnQueryClicked(object sender, EventArgs e)
60 {
61 try
62 {
63 Splasher.Show(typeof(FrmSplash));
64 Splasher.Status = "正在查找数据,请稍等...";
65 System.Threading.Thread.Sleep(450);
66 ucDataGridView.DataSource = null;
67 ucPageControlByCode.SqlWhereStatement = ucCombinQuery1.QueryExpression; //指定查询表达式
68 ucDataGridView.DataSource = ucPageControlByCode.BindPageControl(); //绑定DataGridView
69 }
70 catch (Exception ex)
71 {
72 ucPageControlByCode.SqlWhereStatement = "1<>1";
73 ucDataGridView.DataSource = ucPageControlByCode.BindPageControl(); //绑定DataGridView
74 Splasher.Status = ex.Message;
75 System.Threading.Thread.Sleep(1000);
76 }
77 finally
78 {
79 System.Threading.Thread.Sleep(100);
80 Splasher.Status = "查找完毕...";
81 Splasher.Close();
82 }
83 }
84 }
85 }
最后的效果如下: