MongoDB學習筆記~為IMongoRepository介面新增分頁取集合的方法
對於資料分頁,我們已經見的太多了,幾乎每個列表頁面都要用到分頁,這已經成了一種定理了,在進行大資料展示時,如果不去分頁,而直接把資料載入到記憶體,這簡直是不可以去相向的,呵呵,在很多ORM工具中都對分頁有了更好的支援,如LINQ裡有大家熟悉的take和skip,而在MongoDB裡也有這種概念,它使用limit和skip實現,這在大多數的Mongo客戶端上都集成了這個功能,即幫助我們組合命令引數,並帶我們把分頁取資料的指令發到Mongo伺服器去,實現分頁技術!
添加了分頁後的IMongoRepository介面
/// <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等功能,大家可以放眼去看,放心去想,呵呵!