.Net 分页功能实现

在开发一个项目过程中,出现需要对搜索结果进行分页的需求,实现过程记录如下

1. 首先我们需要有一个分页类PaginatedList<TEntity>, 这个分页类大概包括以下信息

    总行数,当前页面,每页行数,总页数, 前一页,下一页.  为了方便后面操作,我们使它继承自List<T>

写成如下:

 public class PaginatedList<TEntity> : List<TEntity>
{
        public int PageIndex { get; private set; }

        public int PageSize { get; private set; }

        public int TotalCount { get; private set; }

        public int TotalPageCount { get; private set; }

        public bool HasPreviousPage => (PageIndex > 1);

        public bool HasNextPage
        {

            get
            {
                return (PageIndex < TotalPageCount);
            }
        }


        public PaginatedList()
        { }

        public PaginatedList(IEnumerable<TEntity> source, int pageIndex, int pageSize, int totalCount) : this()
        {

            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            AddRange(source);
            PageIndex = pageIndex;
            PageSize = pageSize;
            TotalCount = totalCount;
            TotalPageCount = (int)Math.Ceiling(totalCount / (double)pageSize);
        }
    }

 

整个业务逻辑是这样的,我们在业务逻辑层,会根据一些条件,包括where条件,排序条件去得到一个IQueryable<Entity>. 然后对这个得到的结果IQueryable<Entity>进行分页. 这里面又有2个步骤

2. 从结果集IQueryable<Entity>中得到当前页面的数据. 这个我们可以写一个IQueryable的扩展方法来实现

 public static class QueryableExtensions
    {
 public static IQueryable<TEntity> PaginateQuery<TEntity>(this IQueryable<TEntity> query, int pageOffset, int pageSize)
      {
            var entities = query.Skip(pageOffset).Take(pageSize);
            return entities;
     }
    }

3. 在上一步中得到的当前页面的数据,我们需要得到它的PaginatedList结果集,以便返回给前端使用. 这里还是使用IQueryable的扩展方法来实现,和上面在同一个静态类中

 public static class QueryableExtensions
 {

      

      public static async Task<PaginatedList<TEntity>> ToPaginatedList<TEntity>(this IQueryable<TEntity> query, int pageIndex, int pageSize, int total)
      {
          var list = await query.ToListAsync();
          return new PaginatedList<TEntity>(list, pageIndex, pageSize, total);
      }

     public static IQueryable<TEntity> PaginateQuery<TEntity>(this IQueryable<TEntity> query, int pageOffset, int pageSize)
     {
            var entities = query.Skip(pageOffset).Take(pageSize);
            return entities;
     }
  
 
  
    }

 

4. 这一步完成后,我们来看数据层,数据层需要做以下工作

       4a:  根据where条件,排序条件,include属性等获取需要的数据IQueryable<TEntity>集

       4b:  对得到的IQueryable<TEntity>结果集,调用上面的扩展方法来得到前端需要的PaginatedList数据集

数据层代码写在EntityRepository里面,代码如下

 public class EntityRepository<TEntity> : IRepository<TEntity> where TEntity : Class
    {
        private  IDbSet<TEntity> _dbEntitySet;
        private readonly IDbContext _context;
   public EntityRepository(IRepoUnitOfWork unitOfWork /* , int userId*/)
        {
            _context = unitOfWork.DbContext;
         
            _dbEntitySet = _context.Set<TEntity>();
        }

        private IDbSet<TEntity> Entities
        {
            get { return _dbEntitySet ?? (_dbEntitySet = _context.Set<TEntity>()); }
        }

        public void Dispose()
        {
            //_context.Dispose();
        }

     public async Task<PaginatedList<TEntity>> GetAll<TKey>(int pageIndex, int pageSize, Expression<Func<TEntity, TKey>> keySelector, Expression<Func<TEntity, bool>> predicate, OrderBy orderBy, params Expression<Func<TEntity, object>>[] includeProperties)
        {
           
            var entities = FilterQuery(keySelector, predicate, orderBy, includeProperties);
            var total = entities.Count();// entities.Count() is different than pageSize
            entities = entities.Paginate(pageIndex, pageSize);  //调用上面的扩展方法
            return await entities.ToPaginatedList(pageIndex, pageSize, total); //调用上面的扩展方法
        }

    private IQueryable<TEntity> FilterQuery<TKey>(Expression<Func<TEntity, TKey>> keySelector, Expression<Func<TEntity, bool>> predicate, OrderBy orderBy,
            Expression<Func<TEntity, object>>[] includeProperties)
        {
            var entities = IncludeProperties(includeProperties);
            entities = predicate != null ? entities.Where(predicate) : entities;
            entities = orderBy == OrderBy.Ascending
                ? entities.OrderBy(keySelector)
                : entities.OrderByDescending(keySelector);
            return entities;
        }

        private IQueryable<TEntity> IncludeProperties(params Expression<Func<TEntity, object>>[] includeProperties)
        {
            IQueryable<TEntity> entities = _dbEntitySet;
            foreach (var includeProperty in includeProperties)
            {
                entities = entities.Include(includeProperty);
            }
            return entities;
        }
    }

 

在上面的FilterQuery方法中,我们看到有个参数类型是OrderBy, 这个是我自己定义的Enum类型,代码如下

  public enum OrderBy
    {
        Ascending,
        Descending
    }

就是排序使用

 

最后,我们来看前面业务层使用的例子:

var people = await _personRepository.GetAll(0, 10, i => i.PersonId,
p => p.PersonCircles.Any(a => !a.IsRemoved && a.PersonId == id), OrderBy.Ascending,
x => x.PersonCircles, x => x.Image, x => x.PersonCircles.Select(s => s.Person),
x => x.PersonCircles.Select(s => s.Posts.Select(i => i.Image)));

 

 

 

posted on 2021-05-04 11:38  新西兰程序员  阅读(548)  评论(0编辑  收藏  举报