1.缘起:
当数据源中的数据量多到一定程度时,我们在查询时就经常使用分页策略。如果数据源是一个完整的整体,这没有什么大不了的,我们经常就在做类似的事情。但是,如果数据源不是一个完整的整体,而是由很多有序的片段构成的,并且不同的片段可能位于不同的位置(比如,位于不同的服务器节点上的内存中),甚至,每个片段内的数据还会随着时间的变化而变化的。
在这种假设的情况下,来从这个“虚拟的完整”数据源获取某个分页就不再是那么简单的事情了。一个分页可能位于一个片段的内部的某个区间,也有可能会跨越多个片段。
我们举个例子,以更形象地说明上面描述的问题。
假设,我们有如下几个包含整数的有序片段:
片段A:2、3、5、8
片段B:33、34、45、51、56、78、86
片段C:9、12、14、15、18、23
片段D:90、92、97、108、127
A、B、C、D四个片段,每个片段内部包含的元素的个数都不一样,每个片段内部的整数都是有序的。我们还发现,任意两个片段的取值区间是没有交集的,如我们可以认为A的区间为[2,8],B的区间为[33,86] ,C的区间为[9,23],D的区间为[90,127]。由于任意两个片段的取值区间没有交集,所以,我们可以对这些片段的取值区间进行排序,排序的结果是:A、C、B、D。
现在我们把排序后的A、C、B、D四个片段作为一个虚拟的整体数据源,然后对其进行分页。假设PageSize为5,如果从小到大取第二页的数据应该是:12、14、15、18、23;如果从大到小取第二页的数据应该是:86、78、56、51、45。
你也许会想,这个很容易啊,我把所有片段中的数据取出来,按顺序排列好:
2、3、5、8、9、12、14、15、18、23、33、34、45、51、56、78、86、90、92、97、108、127。
现在想取第几页就可以直接取第几页了,问题解决。是吗?记得我们前面还有一个假设的需求在这里没有考虑进来,那就是每个片段内的数据还会随着时间的变化而变化的,当然,约定好的取值区间是不会变化的。比如,B片段的数据在下一时刻增加了几个数据变成这样:
片段B:33、34、40、42、45、50、51、56、62、78、83、86
片段B增加的数据都是属于其取值区间[33,86]的,所以B的取值区间并不会发生变化。
上面提到的把每个片段中的所有的数据都提取出来排列好的方法就不好用了吧,因为每查询某分页一次,就需要重新排序一次。如果我们的片段非常多,而且每个片段中的数据也非常多,那么,其效率可想而知。
我设计了ESBasic.ObjectManagement.Integration.ScatteredSegmentPicker片段整合提取器来解决类似的问题。
2.适用场合:
当满足以下条件时,你可以使用ScatteredSegmentPicker来对数据源进行分页操作。
(1)数据源由多个片段(Segment)组成。
(2)每个片段内部的数据都是有序的。
(3)任意两个片段的取值区间的交集为空。
(4)片段内的数据可能发生变化,但是其最初预定的取值区间一直是恒定的。
(5)每个片段都有唯一的ID来标志它。
(6)需要从小到大的顺序或从大到小的顺序对所有片段中的数据作为一个整体进行分页。
3.设计思想与实现
根据上述的描述看到,片段是一个核心概念,我们使用ISegment接口来抽象它,ISegment定义如下:
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> ///<summary>
///ISegment片段,一个片段有有序的多个元素TVal构成。
///</summary>
///<typeparamname="TSegmentID">片段标志的类型</typeparam>
///<typeparamname="TVal">构成片段的元素的类型</typeparam>
publicinterfaceISegment<TSegmentID,TVal>
{
///<summary>
///ID每个片段的唯一标志。
///</summary>
TSegmentIDID{get;}
///<summary>
///GetContent获取片段中的所有元素,从小到大排列。
///</summary>
IList<TVal>GetContent();
}
该接口有两个泛型参数:TSegmentID、 TVal。TSegmentID是片段ID的类型,TVal是片段中包含的元素的类型。GetContent方法返回片段中所有元素的列表,并且这个列表中的元素是从小到大的顺序排列的。
我们设计ISegmentContainer接口来提供所有的片段访问,ISegmentContainer接口定义如下:
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> ///<summary>
///ISegmentContainer用于存放片段ISegment的容器。
///</summary>
///<typeparamname="TSegmentID">片段标志的类型</typeparam>
///<typeparamname="TVal">构成片段的元素的类型</typeparam>
publicinterfaceISegmentContainer<TSegmentID,TVal>
{
ISegment<TSegmentID,TVal>GetSmallestSegment();
ISegment<TSegmentID,TVal>GetBiggestSegment();
///<summary>
///GetNextSegment按照fromSmallToBig指定的顺序返回下一个Segment。
///如果返回null,则表示不再有后续的Segment了。
///</summary>
ISegment<TSegmentID,TVal>GetNextSegment(TSegmentIDcurSegmentID,boolfromSmallToBig);
}
这个接口也有两个与ISegment一样的泛型参数,GetSmallestSegment方法和GetBiggestSegment方法用于返回取值区间最小和最大的片段。
从GetNextSegment方法的设计我们知道,ISegmentContainer不是一下子返回所有的片段列表,而是根据当前使用的片段的ID返回下一个片段。之所以这样做,是因为我们一次性获取所有片段列表的代价可能是巨大的,所以一次只返回一个必需的片段。fromSmallToBig参数的值取决于我们是按降序分页还是按升序分页。
如果不再有后续分页,GetNextSegment方法将返回null。
在做了上述这些铺垫后,接下来我们来看本节真正的主角:ScatteredSegmentPicker,正是它将所有的片段整合为一个虚拟的完整数据源,然后对其进行分页提取。
ScatteredSegmentPicker类图如下所示:
PickFromSmallToBig属性表明是要按升序还是降序来提取分页数据。Pick方法执行真正的分页提取动作,startIndex参数是指要以哪条记录作为分页的起始,pickCount参数表示要提取多少条记录,即分页的大小。
Pick方法之所以传递startIndex参数和pickCount参数,而不是传递pageSize和pageIndex,是为了更灵活地支持从任意位置开始的连续记录的提取,而且,这也兼容了分页的提取。比如,你将pageSize*pageIndex作为startIndex参数传入,将pageSize作为pickCount参数传入即是一个标准的分页获取动作。
关于ScatteredSegmentPicker的实现要注意以下几点:
(1)虽然ScatteredSegmentPicker内部实现没有使用到任何加锁机制,但是它可以被使用在多线程的环境中。
(2)ScatteredSegmentPicker的DoPick方法采用遍历策略来提取目标页的数据,PickFromSmallToBig属性决定了遍历片段的方向,是从小到大还是从大到小。
(3)如果要查询的分页不存在,则将返回一个不包含任何元素的List,而不是返回null。
4. 使用时的注意事项
(1)在使用ScatteredSegmentPicker之前,你必须根据你的应用的需求实现ISegment接口和ISegmentContainer接口,然后将ISegmentContainer实例的引用注入到ScatteredSegmentPicker。
(2)虽然我们使用ISegmentContainer来提供所需的每个片段,但是在实现该接口时,不一定非要将所有的片段都存放在ISegmentContainer这个容器中。ISegmentContainer可以作为一个片段获取器的角色从其它地方获取某个片段。比如,某个片段可能位于另外一台服务器的内存中,ISegmentContainer可以通过Remoting的方式从那台服务器获取这个片段的数据。
(3)也许你的片段中的数据不是从小到大或从大到小的顺序,而是依据另外一个性质进行排序,比如由不重要到重要,由不急迫到急迫等,这个只需要与PickFromSmallToBig做正确映射就可以正常使用ScatteredSegmentPicker了。
5.扩展
片段整合提取器 ScatteredSegmentPicker暂时没有任何扩展。
注:ESBasic源码可到http://esbasic.codeplex.com/下载。
ESBasic讨论:37677395
ESBasic开源前言
分享到:
相关推荐
本人将 zhuweisky博主的博客整理成了PDF文件,以便于脱机浏览,没有经过博主的同意就这么做 实在是不好意思^-^ 现将其资料免费下载 以示对博主的尊重 源博客地址:...
在ASP.NET中,类库是代码复用的核心机制,它将常用的功能封装成可重用的类,从而提高开发效率并保持代码的整洁。以下是一些重要的ASP.NET类库及其关键知识点: 1. **System.Web**: 这是ASP.NET中最基础的类库,包含...
.NET公共类库是微软开发平台的核心组成部分,它提供了一系列预定义的类、接口和方法,为开发者构建应用程序提供了丰富的功能支持。这些类库是.NET Framework的一部分,旨在简化开发过程,提高代码重用性,同时也促进...
7. **类库封装**:将上述逻辑封装成一个可重用的类库(DLL),可以使你的代码更整洁,且易于在其他项目中复用。你可以在类库中定义接口和类,比如`IFilePacker`和`FilePackager`,来明确职责和解耦代码。 通过这样...
在.NET开发环境中,类库是一种可重用的代码单元,可以封装特定的功能,方便在多个项目中调用。本主题将深入探讨".NET类库(通用版)"中与MSsql数据处理方法相关的知识点,主要关注`DataOperation.cs`这个文件。 ...
ASP.NET 类库是微软开发的一种用于构建Web应用程序的框架,它是.NET Framework的重要组成部分。这个压缩包文件包含了开发者在使用C#编程时可能会用到的一系列基类,这些类可以帮助简化和加速开发过程,提高代码的...
`Common类库`是一组通用的、可重用的代码模块,它们提供了一般性的功能,如日志记录、配置管理、异常处理等。将这些通用功能封装在独立的类库中,可以提高代码的复用性,降低维护成本,并且使代码更加模块化。 `...
ASP.NET分页类库是一种专门用于处理大量数据并将其按页面显示的工具,它能够显著提升Web应用程序的性能和用户体验。在ASP.NET中,分页是处理大数据集时的一个重要技术,尤其对于那些需要显示表格或者列表数据的场景...
在.NET框架中,类库是核心组件,它们提供了一系列预定义的类型和功能,供开发者在构建应用程序时使用。为了确保类库的质量、可维护性和互操作性,微软通过MSDN(Microsoft Developer Network)发布了一系列设计准则...
ASP.NET 数据层类库控件是一种高效且便捷的开发工具,它可以极大简化数据库操作,减少开发者在编写数据访问层(DAL)代码时的工作量。标题中的"DBHelper"通常指的是一个自定义的数据访问助手类,它封装了常见的SQL...
ASP.NET是微软公司开发的一种用于构建Web应用程序的框架,它基于.NET Framework,为开发者提供了丰富的功能和工具,简化了Web应用的开发流程。本资源"ASP.NET第一步—基于C#和ASP.NET 2.0---光盘内容"显然是一个学习...
在.NET框架中,开发者可以利用丰富的内置类库和第三方库来简化编程工作,提高效率。本文将详细探讨".NET常用...同时,了解并利用好自定义的工具类库,如`GylCRM_Mvc3.Utility`,可以进一步提升代码的可维护性和复用性。
1. **.NET Framework 1.1**:这是.NET Framework的初始版本,引入了公共语言运行时(CLR)和.NET类库,为多种编程语言提供了一个统一的运行平台。它支持ASP.NET、Windows Forms和ADO.NET,极大地简化了Web应用和桌面...
在这个压缩包中,我们看到".NET 公开类库",这表明它包含了一系列供开发者使用的公共类库,这些类库覆盖了common(通用)、data(数据处理)和web(Web应用)三个主要领域。这些类库提供了丰富的功能,简化了开发...
本主题将深入探讨如何使用.NET类库来实现这一功能,特别是通过VC++进行开发。我们将关注ADO.NET、Entity Framework等技术,以及如何创建数据库连接、执行SQL语句和处理结果集。 首先,.NET框架提供了ADO.NET,这是...
在.NET框架中,类库开发是一项关键任务,它涉及到创建可重用的代码模块,以供其他应用程序或开发者使用。遵循良好的设计准则可以确保类库的高质量、可维护性和扩展性。以下是一些核心的.NET类库开发设计准则: 1. *...
综上所述,".NET 数据库操作类库"是为了简化.NET应用与数据库之间的交互而设计的工具,它整合了各种数据库的访问方法,提供了统一的API,便于开发者高效地进行数据操作。通过理解和掌握上述知识点,开发者可以更好地...
ASP.NET MVC 是微软开发的一种用于构建可伸缩、高性能、易于测试和维护的Web应用程序的框架。CMS(Content Management System)则是用于管理网站内容和结构的软件系统,它允许非技术用户通过图形用户界面创建、编辑...
ASP.NET提供了多种控件和类库,如GridView、Repeater、Label、TextBox等,方便开发者创建用户界面并处理用户输入。例如,我们可以使用TextBox控件让用户输入帖子内容,Button控件触发提交操作,Label控件显示反馈...
ASP.NET程序设计是微软开发的一种用于构建Web应用程序的技术,它基于.NET Framework,为开发者提供了高效、易用的工具和框架来创建动态网站、web服务和网络应用。在"ASP.NET程序设计-电子教案"中,重点讲解了ADO.NET...