zoukankan      html  css  js  c++  java
  • .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)));
     
  • 相关阅读:
    LOJ 6192 城市网络(树上倍增)
    SDOI2010代码拍卖会 (计数类DP)
    失控的未来交通工具 (LOJ 508,带权并查集,数论)
    线段树维护区间前k小
    POJ 1966 Cable TV Network (最大流最小割)
    网络流学习笔记
    最大子矩阵和
    POJ 1723 Soldiers (中位数)
    最大子矩阵求法详解
    CH0805 防线 (二分值域,前缀和,特殊性质)
  • 原文地址:https://www.cnblogs.com/wphl-27/p/14729159.html
Copyright © 2011-2022 走看看