回到目錄
對于資料分頁,我們已經見的太多了,幾乎每個清單頁面都要用到分頁,這已經成了一種定理了,在進行大資料展示時,如果不去分頁,而直接把資料加載到記憶體,這簡直是不可以去相向的,呵呵,在很多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等功能,大家可以放眼去看,放心去想,呵呵!
作者:倉儲大叔,張占嶺,
榮譽:微軟MVP
QQ:853066980
支付寶掃一掃,為大叔打賞!
