NopCommerce源码架构详解-数据分页相关源码分析

nop是采用的IPagedList 泛型分页的。今天我们就来看看它是如果实现的?

NopCommerce源码架构详解概述

文章目录

概述

NopCommerce源码架构详解-数据分页相关源码分析。

内容

nop是采用的IPagedList 泛型分页的。今天我们就来看看它是如果实现的?

1、Nop.Core.IPagedList

首先Nop定义了一个使用泛型集合的分页接口IPagedList:

using System.Collections.Generic;

namespace Nop.Core
{
    /// <summary>
    /// Paged list interface
    /// </summary>
    public interface IPagedList<T> : IList<T>
    {
        int PageIndex { get; }
        int PageSize { get; }
        int TotalCount { get; }
        int TotalPages { get; }
        bool HasPreviousPage { get; }
        bool HasNextPage { get; }
    }
}

2、Nop.Core.PagedList

具体的接口IPagedList实现类PagedList:

using System;
using System.Collections.Generic;
using System.linq;

namespace Nop.Core
{
    /// <summary>
    /// Paged list
    /// </summary>
    /// <typeparam name="T">T</typeparam>
    [Serializable]
    public class PagedList<T> : List<T>, IPagedList<T> 
    {
        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">数据源</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页的大小</param>
        public PagedList(IQueryable<T> source, int pageIndex, int pageSize)
        {
            int total = source.Count();
            this.TotalCount = total;
            this.TotalPages = total / pageSize;

            if (total % pageSize > 0)
                TotalPages++;

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;
            this.AddRange(source.Skip(pageIndex * pageSize).Take(pageSize).ToList());
        }

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">数据源</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页的大小</param>
        public PagedList(IList<T> source, int pageIndex, int pageSize)
        {
            TotalCount = source.Count();
            TotalPages = TotalCount / pageSize;

            if (TotalCount % pageSize > 0)
                TotalPages++;

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;
            this.AddRange(source.Skip(pageIndex * pageSize).Take(pageSize).ToList());
        }

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="source">数据源</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页的大小</param>
        /// <param name="totalCount">总记录数</param>
        public PagedList(IEnumerable<T> source, int pageIndex, int pageSize, int totalCount)
        {
            TotalCount = totalCount;
            TotalPages = TotalCount / pageSize;

            if (TotalCount % pageSize > 0)
                TotalPages++;

            this.PageSize = pageSize;
            this.PageIndex = pageIndex;
            this.AddRange(source);
        }

        public int PageIndex { get; private set; }
        public int PageSize { get; private set; }
        public int TotalCount { get; private set; }
        public int TotalPages { get; private set; }

        public bool HasPreviousPage
        {
            get { return (PageIndex > 0); }//是否有前一页
        }
        public bool HasNextPage
        {
            get { return (PageIndex + 1 < TotalPages); }//是否有下一页
        }
    }
}

注意:pageIndex是从0开始的,也就是第一页pageIndex为0,而第二页pageIndex为1。

3、Nop.Core.PagedList在Service中的使用

我们来看看Nop.Core.PagedList在Nop.Services.Catalog中GetProductCategoriesByCategoryId方法是如何调用的分页:

/// <summary>
/// 通过指定产品分类下面的产品分页数据
/// </summary>
/// <param name="categoryId">分类ID</param>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页的大小</param>
/// <param name="showHidden"></param>
/// <returns>返回满足条件的产品</returns>
public virtual IPagedList<ProductCategory> GetProductCategoriesByCategoryId(int categoryId, int pageIndex, int pageSize, bool showHidden = false)
{
    //返回一个空的PagedList集合
    if (categoryId == 0)
        return new PagedList<ProductCategory>(new List<ProductCategory>(), pageIndex, pageSize);

    string key = string.Format(PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY, showHidden, categoryId, pageIndex, pageSize, _workContext.CurrentCustomer.Id, _storeContext.CurrentStore.Id);
    return _cacheManager.Get(key, () =>
    {
        var query = from pc in _productCategoryRepository.Table
                    join p in _productRepository.Table on pc.ProductId equals p.Id
                    where pc.CategoryId == categoryId &&
                          !p.Deleted &&
                          (showHidden || p.Published)
                    orderby pc.DisplayOrder
                    select pc;

        if (!showHidden && (!_catalogSettings.IgnoreAcl || !_catalogSettings.IgnoreStoreLimitations))
        {
            if (!_catalogSettings.IgnoreAcl)
            {
                //ACL (access control list)
                var allowedCustomerRolesIds = _workContext.CurrentCustomer.CustomerRoles
                    .Where(cr => cr.Active).Select(cr => cr.Id).ToList();
                query = from pc in query
                        join c in _categoryRepository.Table on pc.CategoryId equals c.Id
                        join acl in _aclRepository.Table
                        on new { c1 = c.Id, c2 = "Category" } equals new { c1 = acl.EntityId, c2 = acl.EntityName } into c_acl
                        from acl in c_acl.DefaultIfEmpty()
                        where !c.SubjectToAcl || allowedCustomerRolesIds.Contains(acl.CustomerRoleId)
                        select pc;
            }
            if (!_catalogSettings.IgnoreStoreLimitations)
            {
                //Store mapping
                var currentStoreId = _storeContext.CurrentStore.Id;
                query = from pc in query
                        join c in _categoryRepository.Table on pc.CategoryId equals c.Id
                        join sm in _storeMappingRepository.Table
                        on new { c1 = c.Id, c2 = "Category" } equals new { c1 = sm.EntityId, c2 = sm.EntityName } into c_sm
                        from sm in c_sm.DefaultIfEmpty()
                        where !c.LimitedToStores || currentStoreId == sm.StoreId
                        select pc;
            }
            //only distinct categories (group by ID)
            query = from c in query
                    group c by c.Id
                    into cGroup
                    orderby cGroup.Key
                    select cGroup.FirstOrDefault();
            query = query.OrderBy(pc => pc.DisplayOrder);
        }
        //调用PagedList的构造函数返回一个分页之后的IPagedList实例
        var productCategories = new PagedList<ProductCategory>(query, pageIndex, pageSize);
        return productCategories;
    });
}

可以看到上面看到Nop的分页流程大概是这样的:通过筛选数据然后把满足条件的数据源传给PageList,然后通过在PageList里面通过Linq的Skip和Take进行分页,最后只返回指定页码的数据。

原文出处:蓝狐软件工作室【蓝狐】

原文链接:http://m.lanhusoft.com/Article/349.html

本文观点不代表 .Net中文网 立场,转载请联系原作者。

发表评论

登录后才能评论