• .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)));
     
  • 相关阅读:
    Python并发(一)
    Python协程详解(二)
    Python协程详解(一)
    Python装饰器
    ●BZOJ 3676 [Apio2014]回文串
    ●POJ 3974 Palindrome(Manacher)
    ●BZOJ 1692 [Usaco2007 Dec]队列变换
    ●BZOJ 4698 Sdoi2008 Sandy的卡片
    ●BZOJ 4516 [Sdoi2016]生成魔咒
    ●BZOJ 3238 [Ahoi2013]差异
  • 原文地址:https://www.cnblogs.com/wphl-27/p/14729159.html
Copyright © 2020-2023  润新知