MongoDB學習筆記~為(wei)IMongoRepository接口添加(jia)分(fen)頁取集合的方法
對于數據(ju)(ju)分(fen)頁(ye),我(wo)們已(yi)(yi)經見(jian)的(de)(de)太多了,幾乎(hu)每個列表(biao)頁(ye)面都要(yao)用到分(fen)頁(ye),這已(yi)(yi)經成(cheng)了一(yi)種定理了,在(zai)進行大數據(ju)(ju)展(zhan)示時(shi),如(ru)果不去分(fen)頁(ye),而直接把(ba)數據(ju)(ju)加載到內存,這簡直是(shi)不可以去相(xiang)向的(de)(de),呵呵,在(zai)很多ORM工(gong)具中都對分(fen)頁(ye)有了更好的(de)(de)支(zhi)持,如(ru)LINQ里有大家熟悉的(de)(de)take和skip,而在(zai)MongoDB里也有這種概念,它使用limit和skip實現(xian),這在(zai)大多數的(de)(de)Mongo客戶端(duan)上都集(ji)成(cheng)了這個功能,即幫助(zhu)我(wo)們組(zu)合(he)命令參數,并帶我(wo)們把(ba)分(fen)頁(ye)取(qu)數據(ju)(ju)的(de)(de)指令發到Mongo服務器去,實現(xian)分(fen)頁(ye)技術!
添加了分頁后的(de)IMongoRepository接口
/// <summary> /// MongoDB集成(cheng)的查詢方法(fa),大數(shu)據(ju)情況下(xia),有分頁時使用這個(ge)方法(fa) /// </summary> /// <typeparam name="U">匿名對象,用(yong)來為條件(jian)賦值</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集(ji)成(cheng)的查詢方(fang)法,大數(shu)據情況下,有分頁(ye)和(he)排序時使用(yong)這(zhe)個方(fang)法 /// </summary> /// <typeparam name="U">匿名(ming)對象(xiang),用來為條件賦值</typeparam> /// <typeparam name="O">匿(ni)名對象,用來(lai)為排(pai)序賦值(zhi),NoRM.OrderBy枚(mei)舉</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);
看我是(shi)如何去實(shi)現(xian)它的,事實(shi)上是(shi)調(diao)用了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()); }
代(dai)碼主要實(shi)現(xian)的是分頁和排(pai)序功能,其中template是查詢條件,可以(yi)傳入一個匿名對(dui)象(xiang),而orderby參數表(biao)示一個排(pai)序的匿名對(dui)象(xiang),把排(pai)序字段寫到對(dui)象(xiang)里(li)即可,升序為1,降
序為-1,也可以使用它定義(yi)好(hao)的枚(mei)舉來賦(fu)值(zhi),下面我們為上面方法做(zuo)一(yi)個(ge)重載,來針對不需要(yao)排序的需求
public PagedResult<TEntity> GetModel<U>(U template, int pageIndex, int pageSize) { return GetModel(template, new { }, pageIndex, pageSize); }
有了底(di)層的(de)方法,再來看它的(de)返(fan)回(hui)值,如果是分(fen)頁返(fan)回(hui)對象,那么(me)一定要返(fan)回(hui)一個PagedResult泛(fan)型(xing)對象,這個對象主要向外部公(gong)開(kai)一個參數(shu)(shu),如當前頁的(de)數(shu)(shu)據集,當前頁號
每面顯示(shi)記錄(lu)數,總(zong)頁數和總(zong)的記錄(lu)數及(ji)URL條件(jian)集合等。
/// <summary> /// 分(fen)頁結果對象,UI顯示它,BLL為它賦值 /// 陳晴陽(yang)開發(fa),張(zhang)占(zhan)嶺(ling)修改,添加(jia)了AddParameters屬性,用來存儲URL參數(shu) /// </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> /// 初始化一(yi)個(ge)新的(de)<c>PagedResult{T}</c>類型(xing)的(de)實例。 /// </summary> public PagedResult() { Data = new List<T>(); AddParameters = new NameValueCollection(); PageSize = 10; } /// <summary> /// 初始化一個新的<c>PagedResult{T}</c>類型的實例。 /// </summary> /// <param name="totalRecords">總記(ji)錄數。</param> /// <param name="totalPages">頁數。</param> /// <param name="pageSize">頁面大小。</param> /// <param name="pageNumber">頁碼。</param> /// <param name="data">當前頁面的(de)數據(ju)。</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> /// 獲取(qu)或設置頁數(shu)。 /// </summary> public int TotalPages { get; set; } /// <summary> /// 獲取(qu)或設(she)置頁面大小。 /// </summary> public int PageSize { get; set; } /// <summary> /// 獲取或(huo)設置(zhi)頁(ye)碼(ma)。 /// </summary> public int PageIndex { get; set; } /// <summary> /// 獲取或設(she)置(zhi)當前頁面(mian)的數據(ju)。 /// </summary> public List<T> Data { get; set; } /// <summary> /// 分頁參數 /// </summary> public NameValueCollection AddParameters { get; set; } #endregion #region Public Methods /// <summary> /// 確定指定的Object是(shi)否等于當前(qian)的Object。 /// </summary> /// <param name="obj">要與(yu)當前對象(xiang)(xiang)進行比較(jiao)的對象(xiang)(xiang)。</param> /// <returns>如果指(zhi)定的Object與當前(qian)Object相等,則(ze)返(fan)回(hui)true,否則(ze)返(fan)回(hui)false。</returns> /// <remarks>有關此函數(shu)的更多(duo)信息,請參見://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> /// 用作特定類型的哈(ha)希函數。 /// </summary> /// <returns>當前Object的哈希代碼。</returns> /// <remarks>有關此函數的更多信息,請參見://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> /// 確定兩(liang)個對象是否(fou)相等。 /// </summary> /// <param name="a">待(dai)確定的第一個對象。</param> /// <param name="b">待(dai)確(que)定的另(ling)一個對象(xiang)。</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> /// 確定兩個(ge)對象(xiang)是否不相(xiang)等。 /// </summary> /// <param name="a">待確定(ding)的第一個(ge)對(dui)象。</param> /// <param name="b">待確定(ding)的另一個對象(xiang)。</param> /// <returns>如果兩者不相等,則返(fan)回(hui)(hui)true,否則返(fan)回(hui)(hui)false。</returns> public static bool operator !=(PagedResult<T> a, PagedResult<T> b) { return !(a == b); } #endregion #region IEnumerable<T> Members /// <summary> /// 返回一個循(xun)環訪問(wen)集合(he)的枚舉數。 /// </summary> /// <returns>一個可用(yong)于循(xun)環訪問集(ji)合的 IEnumerator 對象。</returns> public IEnumerator<T> GetEnumerator() { return Data.GetEnumerator(); } #endregion #region IEnumerable Members /// <summary> /// 返回(hui)一(yi)個循環訪問集合的(de)枚舉數。 (繼承自 IEnumerable。) /// </summary> /// <returns>一個可用于循(xun)環訪(fang)問(wen)集(ji)合的(de) IEnumerator 對象。</returns> IEnumerator IEnumerable.GetEnumerator() { return Data.GetEnumerator(); } #endregion #region ICollection<T> Members /// <summary> /// 將某(mou)項添加到 ICollection{T} 中。 /// </summary> /// <param name="item">要添(tian)加(jia)到(dao) ICollection{T} 的對(dui)象。</param> public void Add(T item) { Data.Add(item); } /// <summary> /// 從(cong) ICollection{T} 中移除所(suo)有項。 /// </summary> public void Clear() { Data.Clear(); } /// <summary> /// 確定(ding) ICollection{T} 是否包含(han)特定(ding)值。 /// </summary> /// <param name="item">要在 ICollection{T} 中定位的對象。</param> /// <returns>如果在(zai) ICollection{T} 中找(zhao)到 item,則為 true;否則為 false。</returns> public bool Contains(T item) { return Data.Contains(item); } /// <summary> /// 從特(te)定(ding)的 Array 索引開(kai)始,將 ICollection{T} 的元(yuan)素(su)復制(zhi)到一個 Array 中。 /// </summary> /// <param name="array">作(zuo)為從 ICollection{T} 復制的元(yuan)素的目標的一(yi)維 Array。 Array 必須具有從零開始的索(suo)引。</param> /// <param name="arrayIndex">array 中從零開(kai)始的索(suo)引(yin),從此索(suo)引(yin)處(chu)開(kai)始進行復制。</param> public void CopyTo(T[] array, int arrayIndex) { Data.CopyTo(array, arrayIndex); } /// <summary> /// 獲取 ICollection{T} 中包含(han)的元(yuan)素數(shu)。 /// </summary> public int Count { get { return Data.Count; } } /// <summary> /// 獲(huo)取一個值,該值指(zhi)示 ICollection{T} 是(shi)否(fou)為(wei)只讀(du)。 /// </summary> public bool IsReadOnly { get { return false; } } /// <summary> /// 從 ICollection{T} 中移除特定對象的第一個匹配項。 /// </summary> /// <param name="item">要從 ICollection{T} 中移除的(de)對象(xiang)。</param> /// <returns>如(ru)果已從(cong) ICollection{T} 中成功(gong)移除 item,則為 true;否則為 false。 如(ru)果在原始 ICollection{T} 中沒(mei)有找到 item,該方法也會返回 false。 </returns> public bool Remove(T item) { return Data.Remove(item); } #endregion }
有了底層(ceng)方法(fa)和返(fan)回(hui)的(de)對象(xiang),下面就是(shi)前臺顯示了,我們可(ke)(ke)以擴展一個(ge)PagerHelper,重(zhong)新為它起(qi)個(ge)名字叫PagedResultHelper吧,把它的(de)相關PagedList類型對象(xiang)修改成PagedResult對象(xiang)即可(ke)(ke),代碼如下
/// <summary> /// 關(guan)于PagedResult對象的分頁展示 /// 作者(zhe):張(zhang)占嶺,花名(ming):倉(cang)儲大叔 /// </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分頁(ye) /// </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路由支持的(de)分(fen)頁(ye) /// </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); //占(zhan)嶺修改(gai) 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分(fen)頁,不使(shi)用MVC路由(you) /// </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 }
這樣,我們(men)前臺調用(yong)分頁時,還是一句話就搞定了(le),呵呵!
事實上,對于PagedResult我們(men)也可以(yi)用(yong)在其(qi)它(ta)ORM工具上,因為一定(ding)的數據庫和NoSql都開(kai)放(fang)了limit及skip等功(gong)能,大家可以(yi)放(fang)眼去看(kan),放(fang)心去想,呵呵!