ASPNet中DataGrid基于Access的快速分页法.docx

上传人:scccc 文档编号:14417559 上传时间:2022-02-05 格式:DOCX 页数:12 大小:53.20KB
返回 下载 相关 举报
ASPNet中DataGrid基于Access的快速分页法.docx_第1页
第1页 / 共12页
ASPNet中DataGrid基于Access的快速分页法.docx_第2页
第2页 / 共12页
ASPNet中DataGrid基于Access的快速分页法.docx_第3页
第3页 / 共12页
ASPNet中DataGrid基于Access的快速分页法.docx_第4页
第4页 / 共12页
ASPNet中DataGrid基于Access的快速分页法.docx_第5页
第5页 / 共12页
点击查看更多>>
资源描述

《ASPNet中DataGrid基于Access的快速分页法.docx》由会员分享,可在线阅读,更多相关《ASPNet中DataGrid基于Access的快速分页法.docx(12页珍藏版)》请在三一文库上搜索。

1、DataGrid基于Access的快速分页法DataGrid是一个功能非常强大的ASP.NET Web服务器端控件,它除了能够方便地按各种方式格式化显示表格中的数据,还可以对表格中的数据进行动态的排序、编辑和分页。使Web开发人员从繁琐的代码中解放。实现DataGrid的分页功能一直是很多初学ASP.NET的人感到棘手的问题,特别是自定义分页功能,实现方法多种多样,非常灵活。本文将向大家介绍一种DataGird控件在Access数据库下的快速分页法,帮助初学者掌握DataGrid的分页技术。目前的分页方法DataGrid内建的分页方法是使用诸如“ SELECT * FROM 勺SQL语句从数据

2、库表中取出所有的记录到DataSet中,DataGrid控件绑定到该 DataSet之后,它的自动分页功能会帮你从该 DataSet中筛选出当前分页的数据并显示出来,其他没有用的数据将被丢 弃。还有一种方法是使用自定义分页功能,先将DataGrid的AllowCustomPaging属性设置为True ,再利用DataAdapter的Fill方法将数据的筛选工作提前到填充 DataSet时,而不 是让DataGrid帮你筛选:该方法首先将来自查询处的结果填充到DataSet中,再将不需要显示的数据丢弃。当然,自定义分页功能需要完成的事情还不止这些,本文将在后面详细介绍。以上两种方法的工作原理都

3、是先从数据库中取出所有的记录,然后筛选出有用的数据显示出来。可见,两种方法的效率基本上是一致的,因为它们在数据访问阶段并没有采取有效的措施来减少Access对磁盘的访问次数。对于小数量的记录,这种开销可能是比较小的, 如果针对大量数据的分页,开销将会非常巨大,从而导致分页的速度非常的慢。换句话说, 就算每个DataGrid分页面要显示的数据只是一个拥有几万条记录的数据库表的其中10条,每次DataGrid进行分页时还是要从该表中取出所有的记录。很多人已经意识到了这个问题, 并提出了解决方法: 用自定义分页,每次只从数据库中 取出要显示的数据。这样,我们需要在 SQL语句上下功夫了。由于 Acc

4、ess不支持真正的存 储过程,在编写分页算法上就没有 SQL Server那么自由了。 SQL Server可以在存储过程中 利用临时表来实现高效率的分页算法,受到了广泛的采用。而对于 Access ,我们必须想办 法在一条SQL语句内实现最高效的算法。用一条SQL语句取得某段数据的方法有好几种。算法不同,效率也就不同。我经过粗略的测试,发现效率最差的SQL语句执行时耗费的时间大概是效率最高的SQL语句的3倍!而且这个数值会随着记录总数的增加而增加。下面将介绍其中两条常用的SQL语句。为了方便接下来的讨论,我们先约定如下:变量说明变量说明PageSize每贝显不的记录总数MiddleIndex

5、中间虫的索引PageCount分页总数LastIndex最后-页的索引RecordCount数据表的记录总数TableName数据库表名称PageIndex当前页的索引PrimaryKey主键字段名称FirstIndexA页的索引QueryFields要查询的字段集变量定义PageCount(int)Math.Ceiling(double)RecordCount / PageSize)FirstIndex0LastIndexPageCount - 1MiddleIndex(int)Math.Ceiling(double)PageCount / 2)- 1先让我们看看效率最差的SQL语句:SEL

6、ECT TOP PageSize * FROM TableNameWHERE PrimaryKey NOT IN (SELECT TOP PageSize*PageIndex PrimaryKey FROM TableNameORDER BY PrimaryKey ASC)ORDER BY PrimaryKey ASC这条SQL语句慢就慢在 NOTIN这里,主SELECTS句遍历的每个 PrimaryKey的值都要 跟子SELEC砒句的结果集中的每一个 PrimaryKey的值进行比较,这样时间复杂度非常大。 这里不得不提醒一下大家,平时编写SQL语句时应该尽量避免使用NOT IN语句,因为它

7、往往会增加整个SQL语句的时间复杂度。另一种是使用了两个 TO刖三个ORDER BY勺SQL语句,如下所示:SELECT * FROM (SELECT TOP PageSize * FROM (SELECT TOP PageSize*(PageIndex+1) * FROM TableName ORDER BY PrimaryKey ASC)TableA ORDER BY PrimaryKey DESC)TableB ORDER BY PrimaryKey ASC这条SQL语句空间复杂度比较大。如果要显示的分页面刚好是最后一页,那么它的效率比直接SELEC础所有的记录还要低。因此,对于分页算法

8、,我们还应该具体情况具体分析, 不能一概而论。 下面将简单介绍一下相关概念, 如果您对主键和索引非常熟悉, 可以直接跳 过。有关主键和索引的概念在ACCESS中,一个表的主键(PRIMARY KEY又称主索引)必然是唯一索引( UNIQUE INDEX),它的值是不会重复的。除此之外,索引依据索引列的值进行排序,每个索引记录 包含着一个指向它所引用的数据行的指针,这对ORDER BY勺执行非常有帮助。我们可以利用主键这两个特点来实现对某条记录的定位,从而快速地取出某个分页上要显示的记录。举个例子,假设主键字段为INTEGER1,在数据库表中,记录的索引已经按主键字段的 值升序排好 (默认情况下

9、) , 那么主键字段值为“11”的记录的索引,肯定刚好在值为“12”的记录的索引前面 (假设数据库表中存在主键的值为“12 ”的记录)。 如果主键字段不具备UNIQUE约束,数据库表中将有可能存在两个或两个以上主键字段的值为“11”的记录,这样就无法确定这些记录之间的前后位置了。下面就让我们看看如何利用主键来进行数据的分段查询吧。快速分页法的原理其实该分页法是从其他方法衍生而来的。 本人对原来的方法认真地分析, 发现通过优化和改进可以非常有效地提高它的效率。 原算法本身效率很高, 但缺乏对具体问题的具体分析。同一个分页算法, 可能在取第一页的数据时效率非常高, 但是在取最后一页的数据时可能反而

10、效率更低。经过分析,我们可以把分页算法的效率状态分为四种情况:1) PageIndex = FirstIndex2) FirstIndex PageIndex = MiddleIndex3) 3) MiddleIndex PageIndex = LastIndex状态( 1 )和(4)分别表示第一页和最后一页。它们属于特殊情况,我们不必对其使用特殊算法,直接用TOP就可以解决了,不然会把问题复杂化,反而降低了效率。对于剩下的两种状态, 如果分页总数为偶数, 我们可以看作是从数据库表中删掉第一页和最后一页的记录,再把剩下的按前后位置平分为两部分,即前面的一部分,也就是状态(2 ),后面的为另一部

11、分,也就是状态(3 );如果分页总数为奇数,则属于中间页面的记录归于前面的部分。这四种状态分别对应着四组SQL语句,每组SQL语句由升序和降序两条SQL语句组成。下面是一个数据库表, 左边第一列是虚拟的, 不属于该数据库表结构的一部分, 它表示相应记录所在的分页索引。该表将用于接下来的SQL语句的举例中:PageIndexItemIdProductIdPrice00010011$120020011$1310030012$130040012$1120050013$140060013$1230070011$130080012$1540090013$120100013$11由表可得: PageSiz

12、e = 2 , RecordCount = 10 , PageCount = 5升序的SQL语句(1) PageIndex = FirstIndex取第一页的数据是再简单不过了,我们只要用TOPPageSize就可以取出第一页要显示的记录了。SELECT TOP PageSize QueryFields FROM TableName WHERE Condition ORDER BY PrimaryKey ASC(2) FirstIndex PageIndex (SELECT MAX(PrimaryKey) FROM (SELECT TOP PageSize*PageIndex PrimaryK

13、eyFROM TableNameWHERE ConditionORDER BY PrimaryKey ASC)TableA)WHERE ConditionORDER BY PrimaryKey ASC例如:PageIndex=1,红- 黄- 蓝PageindexIte midProductldPrice I0uni0011隼121020011$131030012ii300400122105oai3$14060013$12300700111$13OB001Z$154090013f 12aio0013$11(3) MiddleIndex PageIndex LastIndex接下来看看取数据库表中

14、后半部分记录的SQL语句。该语句跟前面的语句算法的原理是一样的,只是方法稍微不同。先取出当前页之后的所有记录的主键值,再从中选出最小值, 然后取出主键值小于该最小值的前PageSize条记录。SELECT * FROM (SELECT TOP PageSize QueryFieldsFROM TableNameWHERE PrimaryKey (SELECT MIN(PrimaryKey) FROM (FROM TableNameWHERE ConditionORDER BY PrimaryKey DESC)TableA)WHERE ConditionORDER BY PrimaryKey D

15、ESC)TableBORDER BY PrimaryKey ASC之所以把取数据表前半部分记录和取后半部分记录的SQL语句分开写,是因为使用取前半部分记录的SQL语句时,当前页前面的记录数目随页数递增,而我们还要从这些记录中取出它们的主键字段的值再从中选出最大值。这样一来,分页速度将随着页数的增加而减慢。因此我没有这样做,而是在当前页索引大于中间页索引时( MiddleIndex 黄- 蓝PageindexIte midProductldPrice0lioi0011$12020011$1310300121$13040012$11工0013$14060013$123CI070011$130840

16、90013f 12 100013Qi(4) PageIndex = LastIndex取最后一页的记录可以简单地使用类似状态(1)的做法:SELECT * FROM (SELECT TOP PageSize QueryFieldsFROM TableNameWHERE ConditionORDER BY PrimaryKey DESC)TableA ORDER BY PrimaryKey ASC不过,这样产生的最后一页不一定是实际意义上的最后一页。因为最后一页的记录数未必刚好跟PageSize相等,而上面的 SQL语句是直接取得倒数的 PageSize条记录。如果想 要精确地取得最后一页的记录

17、,应该在先计算出该页的记录数,作为TOP语句的条件:SELECT * FROM (SELECT TOP (RecordCount-PageSize*LastIndex) QueryFieldsFROM TableName WHERE ConditionORDER BY PrimaryKey DESC)TableA ORDER BY PrimaryKey ASC降序的SQL语句降序的SQL语句跟升序的大同小异,这里就不在罗嗦了J(1) PageIndex = FirstIndexSELECT TOP PageSize QueryFields FROM TableName WHERE Condit

18、ion ORDER BY PrimaryKey DESC(2) FirstIndex PageIndex = MiddleIndexSELECT TOP PageSize QueryFieldsFROM TableNameWHERE PrimaryKey (SELECT MIN(PrimaryKey) FROM (SELECT TOP PageSize*PageIndex PrimaryKeyFROM TableNameWHERE ConditionORDER BY PrimaryKey DESC)TableA)WHERE ConditionORDER BY PrimaryKey DESC(3

19、) MiddleIndex PageIndex (SELECT MAX(PrimaryKey) FROM (SELECT TOP (RecordCount-PageSize*(PageIndex+1) PrimaryKeyFROM TableNameWHERE ConditionORDER BY PrimaryKey ASC)TableA)WHERE ConditionORDER BY PrimaryKey ASC)TableB ORDER BY PrimaryKey DESCSELECT * FROM ( SELECT TOP (RecordCount-PageSize*LastIndex)

20、 QueryFieldsFROM TableName WHERE Condition ORDER BY PrimaryKey ASC)TableA ORDER BY PrimaryKey DESC如何动态产生上述的 SQL语句?看了上面的SQL语句之后,相信大家已经基本明白该分页法的原理了。下面,我们将要设计一个动态生成 SQL语句的类FastPaging 。该类有一个公有静态方法,它根据您给出的 条件动态生成SQL语句,作为方法的返回值。/产生根据指定字段排序并分页查询的SELECT语句。public static String Paging(int pageSize,/每页要显示的记录的数

21、目。int pageIndex,/要显示的页的索引。int recordCount, String tableName, /String queryFields, /String primaryKey, / bool ascending, /String condition /)数据表中的记录总数。要查询的数据表。要查询的字段。主键字段。是否为升序排列。查询的筛选条件。StringBuilder sb = new StringBuilder();int pageCount = GetPageCount(recordCount,pageSize); /分页的总数int middleIndex =

22、 GetMidPageIndex(pageCount); /中间页的索引int firstIndex = 0; / 第一页的索引int lastIndex = pageCount - 1; /最后一页的索引if (pageIndex firstIndex & pageindex ().Append( SELECT MAX();elsesb.Append( = lastindex) /代码略return sb.ToString();除了 Paging方法还有另外几个方法:/根据记录总数和分页大小计算分页数。public static int GetPageCount(int recordCoun

23、t, int pageSize) return (int)Math.Ceiling(double)recordCount/pageSize);/计算中间页的页索引。public static int GetMidPageIndex(int pageCount) return (int)Math.Ceiling(double)pageCount/2) - 1;/获取排序白方式(ASC表示升序,DESC表示降序)public static String GetSortType(bool ascending) return (ascending ? ASC : DESC);/获取一个布尔值,该值指示

24、排序的方式是否为升序。public static bool IsAscending(String orderType) return (orderType.ToUpper() = DESC) ? false : true);让DataGrid工作起来有了上面的类,实现分页的工作就简单多了。首先,我们要将DataGrid的AllowPaging属性和AllowCustomPaging属性为True ,除此之外,为了体现出升序和降序的功能,还需 要将AllowSorting 属性也设置为True。然后在每次分页时,我们需要产生一个 OleDbDataReader对象或 DataView对象绑定到

25、DataGrid ,作为DataGrid的数据源。这里需 要用FastPaging类的Paging方法根据条件产生一个SQL语句,并赋给 OleDbCommand寸象的 CommandTex墉性:cmd.CommandText = FastPaging.Paging(DataGrid1.PageSize,(int)ViewStateCurrentPageIndex,DataGrid1.VirtualItemCount,Items,ItemId, ProductId, Price,ItemId,FastPaging.IsAscending(OrderType), );在上面的程序段中,ViewS

26、tateCurrentPageIndex 的值在 DataGrid的Page事件处 理程序中被更新为e.NewPageIndex 。为了方便处理 ViewState 的空值,最好把对 ViewStateCurrentPageIndex的存取操作和空值判断封装在一个属性里。DataGrid1.VirtualItemCount应该设置为数据库表中的记录总数。DataGrid通过它和PageSize属性可以虚拟出 DataGrid的分页数。VirtualItemCount的值是在 Page的Load事件处理程序中被设置的,而该值的大小需要经过一次数据库访问才能得到。为了提高性能,可以只在第一次加载页面的时候设置该值。总结DataGrid基于Access的快速分页法到这里就介绍完了。当然,这种方法并不能“包治 百病”,可能对于您的要实现的功能,还有其它更好的方法。这就需要大家在平时工作和学 习中不断总结经验,在解决实际问题时尽可能找到最有效的方法。这也是本文的方法中所贯穿的思想。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 社会民生


经营许可证编号:宁ICP备18001539号-1