MongoDB学习笔记~为IMongoDBRepository接口添加分页取集合的方法

对于数据分页,我们已经见的太多了,几乎每个列表页面都要用到分页,这已经成了一种定理了,在进行大数据展示时,如果不去分页,而直接把数据加载到内存,这简直是不可以去相向的,呵呵,在很多ORM工具中都对分页有了更好的支持,如LINQ里有大家熟悉的take和skip,而在MongoDB里也有这种概念,它使用limit和skip实现,这在大多数的Mongo客户端上都集成了这个功能,即帮助我们组合命令参数,并带我们把分页取数据的指令发到Mongo服务器去,实现分页技术!

添加了分页后的IMongoDBRepository接口

        /// <summary>
        /// MongoDB集成的查询方法,大数据情况下,有分页时使用这个方法
        /// </summary>
        /// <typeparam name="U">匿名对象,用来为条件赋值</typeparam>
        /// <param name="template">条件对象</param>
        /// <param name="limit"></param>
        /// <param name="skip"></param>
        /// <returns></returns>
        PagedResult<TEntity> GetModel<U>(U template, int pageIndex, int pageSize);
        /// <summary>
        /// MongoDB集成的查询方法,大数据情况下,有分页和排序时使用这个方法
        /// </summary>
        /// <typeparam name="U">匿名对象,用来为条件赋值</typeparam>
        /// <typeparam name="O">匿名对象,用来为排序赋值,NoRM.OrderBy枚举</typeparam>
        /// <param name="template">条件对象</param>
        /// <param name="orderby">排序对象</param>
        /// <param name="limit"></param>
        /// <param name="skip"></param>
        /// <returns></returns>
        PagedResult<TEntity> GetModel<U, O>(U template, O orderby, int pageIndex, int pageSize);

看我是如何去实现它的,事实上是调用了Mongo客户端封装的Find<T, U, O>(this IMongoCollection<T> collection, U template, O orderby, int limit, int skip);方法

实现的,我们来看一下代码

  public PagedResult<TEntity> GetModel<U, O>(U template, O orderby, int pageIndex, int pageSize)
        {
            var skip = (pageIndex - 1) * pageSize;
            var limit = pageSize;
            var recordCount = _table.Count();
            return new PagedResult<TEntity>(
                recordCount,
                (int)(recordCount + pageSize - 1) / pageSize,
                pageSize,
                pageIndex,
                _table.Find(template, orderby, limit, skip).ToList());
        }

代码主要实现的是分页和排序功能,其中template是查询条件,可以传入一个匿名对象,而orderby参数表示一个排序的匿名对象,把排序字段写到对象里即可,升序为1,降

序为-1,也可以使用它定义好的枚举来赋值,下面我们为上面方法做一个重载,来针对不需要排序的需求

   public PagedResult<TEntity> GetModel<U>(U template, int pageIndex, int pageSize)
        {
            return GetModel(template, new { }, pageIndex, pageSize);
        }

有了底层的方法,再来看它的返回值,如果是分页返回对象,那么一定要返回一个PagedResult泛型对象,这个对象主要向外部公开一个参数,如当前页的数据集,当前页号

每面显示记录数,总页数和总的记录数及URL条件集合等。

    /// <summary>
    /// 分页结果对象,UI显示它,BLL为它赋值
    /// 陈晴阳开发,张占岭修改,添加了AddParameters属性,用来存储URL参数
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class PagedResult<T> : IEnumerable<T>, ICollection<T>
    {
        #region Public Fields
        /// <summary>
        /// 获取一个当前类型的空值。
        /// </summary>
        public static readonly PagedResult<T> Empty = new PagedResult<T>(0, 0, 0, 0, null);
        #endregion

        #region Ctor
        /// <summary>
        /// 初始化一个新的<c>PagedResult{T}</c>类型的实例。
        /// </summary>
        public PagedResult()
        {
            Data = new List<T>();
            AddParameters = new NameValueCollection();
            PageSize = 10;
        }
        /// <summary>
        /// 初始化一个新的<c>PagedResult{T}</c>类型的实例。
        /// </summary>
        /// <param name="totalRecords">总记录数。</param>
        /// <param name="totalPages">页数。</param>
        /// <param name="pageSize">页面大小。</param>
        /// <param name="pageNumber">页码。</param>
        /// <param name="data">当前页面的数据。</param>
        public PagedResult(long totalRecords, int totalPages, int pageSize, int pageNumber, List<T> data)
        {
            this.TotalPages = totalPages;
            this.TotalRecords = totalRecords;
            this.PageSize = pageSize;
            this.PageIndex = pageNumber;
            this.Data = data;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// 获取或设置总记录数。
        /// </summary>
        public long TotalRecords { get; set; }
        /// <summary>
        /// 获取或设置页数。
        /// </summary>
        public int TotalPages { get; set; }
        /// <summary>
        /// 获取或设置页面大小。
        /// </summary>
        public int PageSize { get; set; }
        /// <summary>
        /// 获取或设置页码。
        /// </summary>
        public int PageIndex { get; set; }
        /// <summary>
        /// 获取或设置当前页面的数据。
        /// </summary>
        public List<T> Data { get; set; }
        /// <summary>
        /// 分页参数
        /// </summary>
        public NameValueCollection AddParameters { get; set; }
        #endregion

        #region Public Methods
        /// <summary>
        /// 确定指定的Object是否等于当前的Object。
        /// </summary>
        /// <param name="obj">要与当前对象进行比较的对象。</param>
        /// <returns>如果指定的Object与当前Object相等,则返回true,否则返回false。</returns>
        /// <remarks>有关此函数的更多信息,请参见:http://msdn.microsoft.com/zh-cn/library/system.object.equals。
        /// </remarks>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj))
                return true;
            if (obj == (object)null)
                return false;
            var other = obj as PagedResult<T>;
            if (other == (object)null)
                return false;
            return this.TotalPages == other.TotalPages &&
                this.TotalRecords == other.TotalRecords &&
                this.PageIndex == other.PageIndex &&
                this.PageSize == other.PageSize &&
                this.Data == other.Data;
        }

        /// <summary>
        /// 用作特定类型的哈希函数。
        /// </summary>
        /// <returns>当前Object的哈希代码。</returns>
        /// <remarks>有关此函数的更多信息,请参见:http://msdn.microsoft.com/zh-cn/library/system.object.gethashcode。
        /// </remarks>
        public override int GetHashCode()
        {
            return this.TotalPages.GetHashCode() ^
                this.TotalRecords.GetHashCode() ^
                this.PageIndex.GetHashCode() ^
                this.PageSize.GetHashCode();
        }

        /// <summary>
        /// 确定两个对象是否相等。
        /// </summary>
        /// <param name="a">待确定的第一个对象。</param>
        /// <param name="b">待确定的另一个对象。</param>
        /// <returns>如果两者相等,则返回true,否则返回false。</returns>
        public static bool operator ==(PagedResult<T> a, PagedResult<T> b)
        {
            if (ReferenceEquals(a, b))
                return true;
            if ((object)a == null || (object)b == null)
                return false;
            return a.Equals(b);
        }

        /// <summary>
        /// 确定两个对象是否不相等。
        /// </summary>
        /// <param name="a">待确定的第一个对象。</param>
        /// <param name="b">待确定的另一个对象。</param>
        /// <returns>如果两者不相等,则返回true,否则返回false。</returns>
        public static bool operator !=(PagedResult<T> a, PagedResult<T> b)
        {
            return !(a == b);
        }
        #endregion

        #region IEnumerable<T> Members
        /// <summary>
        /// 返回一个循环访问集合的枚举数。
        /// </summary>
        /// <returns>一个可用于循环访问集合的 IEnumerator 对象。</returns>
        public IEnumerator<T> GetEnumerator()
        {
            return Data.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members
        /// <summary>
        /// 返回一个循环访问集合的枚举数。 (继承自 IEnumerable。)
        /// </summary>
        /// <returns>一个可用于循环访问集合的 IEnumerator 对象。</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return Data.GetEnumerator();
        }

        #endregion

        #region ICollection<T> Members
        /// <summary>
        /// 将某项添加到 ICollection{T} 中。
        /// </summary>
        /// <param name="item">要添加到 ICollection{T} 的对象。</param>
        public void Add(T item)
        {
            Data.Add(item);
        }

        /// <summary>
        /// 从 ICollection{T} 中移除所有项。
        /// </summary>
        public void Clear()
        {
            Data.Clear();
        }

        /// <summary>
        /// 确定 ICollection{T} 是否包含特定值。
        /// </summary>
        /// <param name="item">要在 ICollection{T} 中定位的对象。</param>
        /// <returns>如果在 ICollection{T} 中找到 item,则为 true;否则为 false。</returns>
        public bool Contains(T item)
        {
            return Data.Contains(item);
        }

        /// <summary>
        /// 从特定的 Array 索引开始,将 ICollection{T} 的元素复制到一个 Array 中。
        /// </summary>
        /// <param name="array">作为从 ICollection{T} 复制的元素的目标的一维 Array。 Array 必须具有从零开始的索引。</param>
        /// <param name="arrayIndex">array 中从零开始的索引,从此索引处开始进行复制。</param>
        public void CopyTo(T[] array, int arrayIndex)
        {
            Data.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// 获取 ICollection{T} 中包含的元素数。
        /// </summary>
        public int Count
        {
            get { return Data.Count; }
        }

        /// <summary>
        /// 获取一个值,该值指示 ICollection{T} 是否为只读。
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        /// 从 ICollection{T} 中移除特定对象的第一个匹配项。
        /// </summary>
        /// <param name="item">要从 ICollection{T} 中移除的对象。</param>
        /// <returns>如果已从 ICollection{T} 中成功移除 item,则为 true;否则为 false。 如果在原始 ICollection{T} 中没有找到 item,该方法也会返回 false。 </returns>
        public bool Remove(T item)
        {
            return Data.Remove(item);
        }

        #endregion
    }

有了底层方法和返回的对象,下面就是前台显示了,我们可以扩展一个PagerHelper,重新为它起个名字叫PagedResultHelper吧,把它的相关PagedList类型对象修改成PagedResult对象即可,代码如下

  /// <summary>
    /// 关于PagedResult对象的分页展示
    /// 作者:张占岭,花名:仓储大叔
    /// </summary>
    public static class PagedResultHelper
    {

        #region Ajax分页
        /// <summary>
        /// AJAX分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="html"></param>
        /// <param name="pagedList"></param>
        /// <param name="UpdateTargetId"></param>
        /// <returns></returns>
        public static MvcHtmlString AjaxPagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, string UpdateTargetId, bool isDisplayCompletePage)
        {
            var ui = new UIHelper(html.ViewContext.RequestContext.HttpContext.Request.Url.ToString(), UpdateTargetId, pagedList.AddParameters);
            if (!isDisplayCompletePage)
                return MvcHtmlString.Create(ui.GetPage(pagedList.PageIndex, pagedList.PageSize, (int)pagedList.TotalRecords, false));
            else
                return MvcHtmlString.Create(ui.GetPage(pagedList.PageIndex, pagedList.PageSize, (int)pagedList.TotalRecords));
        }

        public static MvcHtmlString AjaxPager<T>(this HtmlHelper html, PagedResult<T> pagedList, string UpdateTargetId)
        {
            return AjaxPagerResult<T>(html, pagedList, UpdateTargetId, true);
        }
        /// <summary>
        /// AJAX分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="html"></param>
        /// <param name="pagedList"></param>
        /// <param name="UpdateTargetId"></param>
        /// <param name="ActionName"></param>
        /// <param name="ControllerName"></param>
        /// <returns></returns>
        public static MvcHtmlString AjaxPagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, string UpdateTargetId, string ActionName, string ControllerName, bool isDisplayCompletePage, bool isTop)
        {
            var mvcUrl = new UrlHelper(html.ViewContext.RequestContext).Action(ActionName, ControllerName); //占岭修改
            var localUrl = string.Format(@"{0}://{1}", html.ViewContext.RequestContext.HttpContext.Request.Url.Scheme, html.ViewContext.RequestContext.HttpContext.Request.Url.Authority);
            var url = string.Format("{0}{1}{2}", localUrl, mvcUrl, html.ViewContext.RequestContext.HttpContext.Request.Url.Query);
            var ui = new UIHelper(url, UpdateTargetId, pagedList.AddParameters);
            return MvcHtmlString.Create(ui.GetPage(pagedList.PageIndex, pagedList.PageSize, (int)pagedList.TotalRecords, isDisplayCompletePage, false, isTop));
        }
        public static MvcHtmlString AjaxPagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, string UpdateTargetId, string ActionName, string ControllerName, bool isDisplayCompletePage)
        {
            return AjaxPagerResult<T>(html, pagedList, UpdateTargetId, ActionName, ControllerName, true, false);
        }
        /// <summary>
        /// ajax方式,MVC路由支持的分页
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="html"></param>
        /// <param name="pagedList"></param>
        /// <param name="UpdateTargetId"></param>
        /// <param name="ActionName"></param>
        /// <param name="ControllerName"></param>
        /// <returns></returns>
        public static MvcHtmlString AjaxPagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, string UpdateTargetId, string ActionName, string ControllerName)
        {
            var mvcUrl = new UrlHelper(html.ViewContext.RequestContext).Action(ActionName, ControllerName); //占岭修改
            var localUrl = string.Format(@"{0}://{1}", html.ViewContext.RequestContext.HttpContext.Request.Url.Scheme, html.ViewContext.RequestContext.HttpContext.Request.Url.Authority);
            var url = string.Format("{0}{1}{2}", localUrl, mvcUrl, html.ViewContext.RequestContext.HttpContext.Request.Url.Query);
            var ui = new UIHelper(url, UpdateTargetId, pagedList.AddParameters);

            return MvcHtmlString.Create(ui.GetPage(pagedList.PageIndex
               , pagedList.PageSize
               , (int)pagedList.TotalRecords
               , 0
               , new UrlHelper(html.ViewContext.RequestContext)
               , html.ViewContext.RouteData.Values["action"].ToString()
               , html.ViewContext.RouteData.Values["controller"].ToString(), true, false, null));

        }

        #endregion

        #region Html分页
        /// <summary>
        /// Html分页,不使用MVC路由
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="html"></param>
        /// <param name="pagedList"></param>
        /// <returns></returns>
        public static MvcHtmlString PagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList)
        {
            return PagerResult<T>(html, pagedList, false);
        }
        public static MvcHtmlString PagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, string className)
        {
            return PagerResult<T>(html, pagedList, false, className);
        }
        public static MvcHtmlString PagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, bool router, string className)
        {
            return PagerResult<T>(html, pagedList, router, true, className);
        }
        /// <summary>
        /// Html分页,router为true表示走MVC路由
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="html"></param>
        /// <param name="pagedList"></param>
        /// <param name="router">路由</param>
        /// <param name="className">CSS类名</param>
        /// <returns></returns>
        public static MvcHtmlString PagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, bool router, bool isCompleteDisplay, string className)
        {
            if (pagedList == null)
                return null;
            UIHelper ui = new UIHelper(html.ViewContext.RequestContext.HttpContext.Request.Url.ToString(), pagedList.AddParameters);
            if (router)
                return MvcHtmlString.Create(ui.GetPage(pagedList.PageIndex
                    , pagedList.PageSize
                    , (int)pagedList.TotalRecords
                    , 0
                    , new UrlHelper(html.ViewContext.RequestContext)
                    , html.ViewContext.RouteData.Values["action"].ToString()
                    , html.ViewContext.RouteData.Values["controller"].ToString(), isCompleteDisplay, false, className));
            return MvcHtmlString.Create(ui.GetPage(pagedList.PageIndex, pagedList.PageSize, (int)pagedList.TotalRecords, isCompleteDisplay, className));
        }
        public static MvcHtmlString PagerResult<T>(this HtmlHelper html, PagedResult<T> pagedList, bool router)
        {
            return PagerResult<T>(html, pagedList, router, null);
        }
        #endregion

    }

这样,我们前台调用分页时,还是一句话就搞定了,呵呵!

事实上,对于PagedResult我们也可以用在其它ORM工具上,因为一定的数据库和NoSql都开放了limit及skip等功能,大家可以放眼去看,放心去想,呵呵!

时间: 2024-10-29 19:07:47

MongoDB学习笔记~为IMongoDBRepository接口添加分页取集合的方法的相关文章

MongoDB学习笔记~为IMongoRepository接口添加了排序和表达式树,针对官方驱动

MongoDB的官方驱动,语法更好,更强 之前写过关于IMongoRepository仓储的文章,在mongodb的驱动选择上使用了NoRM,但是进行$ref引用类型导航时出现了问题,它对引用类型属性支持不是很好,还是使用几年前的泛型技术而没有使用Attribute,在这个方面官方驱动做的更好,所以,我还是使用官方驱动又实现了一次IMongoRepository,把一些实现的细节封装在了底层,我们叫这个官方仓储为MongoOfficialRepository,呵呵,谁叫你来的晚呢,MongoRe

MongoDB学习笔记~为IMongoRepository接口添加了增删改方法,针对官方驱动

上一讲说了MongoDB官方驱动的查询功能,这回说一下官方驱动的增删改功能,驱动在升级为2.0后,相应的insert,update和delete都只有了异步版本(或者叫并行版本),这当然也是跟着.net走的正方向,大事所趋,但有时,我们的前台已经使用同步方式实现了,为了不改变前台代码,所以,后台的异步版本可能不是我们所需要的,所以,我们需要将它进行一些改造,把异步改为同步,即主线程等待异步方法执行结束后,再进行下面的代码,这样,可以保证方法的正确性. 由于insert,update,delete

MongoDB学习笔记~大叔分享批量添加—批量更新—批量删除

回到目录 说它是批量操作,就是说将集合对象一次提交到服务器,并对数据进行持久化,如果您的代码是一次一次的提交,那不算是批量操作!在之前的mongodb仓储中并没有对批量更新和批量删除进行实现,而今天在项目中,还是实现了这种批量的操作,并且已经通过测试,下面公开一下源代码 public void Insert(IEnumerable<TEntity> item) { var list = new List<WriteModel<TEntity>>(); foreach (

MongoDB学习笔记~自己封装的Curd操作(查询集合对象属性,更新集合对象)

回到目录 我不得不说,mongodb官方驱动在与.net结合上做的不是很好,不是很理想,所以,我决定对它进行了二次封装,这是显得很必然了,每个人都希望使用简单的对象,而对使用复杂,麻烦,容易出错的对象尽而远之,这是正常的,人都是喜欢懒惰的,就像程序员,也是一样,喜欢偷懒,可能说,偷懒是程序员进步的一个标志,呵呵. 下面我是总结的几种标准的操作,主要是针对我封装的官方驱动而方的(MongoOfficialRepository<TEntity>) 1  插入对象和子对象 /// <summa

MongoDB学习笔记系列

回到占占推荐博客索引 该来的总会来的,Ef,Redis,MVC甚至Sqlserver都有了自己的系列,MongoDB没有理由不去整理一下,这个系列都是平时在项目开发时总结出来的,希望可以为各位一些帮助和启发,文章中有对新技术的研究(Mongo驱动),对老技术的回顾(代码重构),还有对架构设计的阐述等(面向接口编程,对扩展开放,对修改关闭,所以出现了IMongoRepository接口). MongoDB学习笔记系列~目录 MongoDB学习笔记~环境搭建 (2015-03-30 10:34) M

MongoDB学习笔记一:MongoDB的下载和安装

趁着这几天比较空闲,准备学习一下MongoDB数据库,今天就简单的学习了一些MongoDB的下载和安装,并创建了存储MongoDB的数据仓库.将自己今天学习到的写成博客分享给大家. 一.MongoDB的下载和安装 MongoDB的下载地址为:http://www.mongodb.org/ 1.进入官网的首页后,在首页的右上方单击Downloads连接,如图所示: 2.在页面中可以看到目前最新的版本和以前发布过的版本,这里选择最新版本,windows 32位的进行下载,文件的格式为ZIP格式的,单

【Cocos2D-X 学习笔记】为精灵添加单点触控

由于Cocos2d-x处于新学的阶段,因此最近也无法进行系统地更新,只会选择一些典型的Demo贴上来,一来是与大家分享,而来也可以作为以后回顾时的参考. 今天介绍一下Cocos2d-x的触摸事件处理,了解Android开发的朋友们知道,Android里会用一个OnClickListener()进行事件监听,而在J2SE中也会有Event类实现专门的监听处理.在Cocos2d-x中,因为是游戏引擎,用户在玩游戏时总是要通过屏幕与游戏进行交互,可想而知触摸事件是主要处理的事件.这里主要讲一下如何为精

mongodb学习笔记系列一

一.简介和安装 ./bin/mongod --dbpath /path/to/database --logpath /path/to/log --fork --port 27017 mongodb非常的占磁盘空间, 刚启动后要占3-4G左右,--smallfiles 二.基本命令 1.登录mongodb client /use/local/mongo 2.查看当前数据库 show databases; show dbs; 两个可能 3.admin是和管理有关的库,local 是放schema有关

[Spring Data MongoDB]学习笔记--牛逼的MongoTemplate

MongoTemplate是数据库和代码之间的接口,对数据库的操作都在它里面. 注:MongoTemplate是线程安全的. MongoTemplate实现了interface MongoOperations,一般推荐使用MongoOperations来进行相关的操作. MongoOperations mongoOps = new MongoTemplate(new SimpleMongoDbFactory(new Mongo(), "database")); MongoDB docu