tnblog
首页
登录

新型分页,排序,搜索,以及上一页与下一页

89人阅读 2019/10/29 11:47 总访问:10948 评论:0 手机 收藏
分类: .net后台框架


1.分页数据接口,方法与实现类

public interface IPostRepository
{
    Task<PaginatedList<Post>> GetAllPosts(PostParameters postParameters);
    Task<Post> GetPostByIdAsync(int id);
    void AddPost(Post post);
}

通过PostRepository.cs实现IPostRepository.cs类:

public class PostRepository : IPostRepository
{
    private readonly MyContext _myContext;
    public PostRepository(MyContext myContext)
    {
        this._myContext = myContext;
    }

    public void AddPost(Post post)
    {
        _myContext.Posts.Add(post);
    }

    public async Task<Post> GetPostByIdAsync(int id)
    {
        return await _myContext.Posts.FindAsync(id);
    } 

    public async Task<PaginatedList<Post>> GetAllPosts(PostParameters postParameters)
    {
        #region 翻页,排序
        var query = _myContext.Posts.OrderBy(x => x.Id);
        var count = await query.CountAsync();
        #endregion
        //return await _myContext.Posts.ToListAsync();
        var data = await query
            .Skip(postParameters.PageIndex * postParameters.PageSize)
            .Take(postParameters.PageSize)
            .ToListAsync();
        return new PaginatedList<Post>(postParameters.PageIndex,postParameters.PageSize,count,data);
    }
}

PaginatedList.cs

public class PaginatedList<T> : List<T> where T :class
{
    public int PageSize { get; set; }
    public int PageIndex { get; set; }
    private int _totalItemsCount;
    public int TotalItemsCount
    {
        get=>_totalItemsCount;
        set=>_totalItemsCount = value >=0?value:0;
    }
    public int PageCount => TotalItemsCount / PageSize + (TotalItemsCount % PageSize > 0 ? 1 : 0);
    //是否有上一页
    public bool HasPrevious => PageIndex > 0;
    //是否有下一页
    public bool HasNext => PageIndex <PageCount - 1;

    public PaginatedList(int pageIndex,int pageSize,int totalItemCount,IEnumerable<T> data)
    {
        PageIndex = pageIndex;
        PageSize = pageSize;
        TotalItemsCount = totalItemCount;
        AddRange(data);
    }
}

PostParameters.cs类实现QueryParameters.cs

public abstract class QueryParameters : System.ComponentModel.INotifyPropertyChanged
{
    private const int DefaultPageSize = 10;
    private const int DefaultMaxPageSize = 100;

    private int _pageIndex;
    public int PageIndex
    {
        get => _pageIndex;
        set => _pageIndex = value >= 0 ? value : 0;
    }
    private int _pageSize = DefaultPageSize;
    public virtual int PageSize
    {
        get => _pageSize;
        set => SetField(ref _pageSize, value);
    }
    private string _orderBy;
    public string OrderBy
    {
        get => _orderBy;
        set => _orderBy = value ?? nameof(IEntity.Id);
    }
    private int _maxPageSize = DefaultMaxPageSize;

    public event PropertyChangedEventHandler PropertyChanged;

    protected internal virtual int MaxPageSize
    {
        get => _maxPageSize;
        set => SetField(ref _maxPageSize, value);
    }
    public string Fields { get; set; }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field))
        {
            return false;
        }
        field = value;
        OnPropertyChanged(propertyName);
        if (propertyName == nameof(PageSize) || propertyName == nameof(MaxPageSize))
        {
            SetPageSize();
        }
        return true;
    }

    private void SetPageSize()
    {
        if (_maxPageSize <= 0)
        {
            _maxPageSize = DefaultMaxPageSize;
        }
        if (_pageSize <= 0)
        {
            _pageSize = DefaultPageSize;
        }
        _pageSize = _pageSize > _maxPageSize ? _maxPageSize : _pageSize;
    }
}
public class PostParameters: QueryParameters
{
}

2.控制器的实现

Startup.cs类中ConfigureServices方法实现注入

services.AddScoped<IPostRepository, PostRepository>();

WebApiPostController控制器

private readonly IPostRepository _PostRepository;
private readonly IUnitOfWOrk _unitOfWork;
private readonly ILogger _Logger;
private readonly IConfiguration _configuration;
private readonly IMapper _mapper;
public PostController(IUnitOfWOrk UnitOfWOrk
    , IPostRepository PostRepository
    ,ILoggerFactory loggerFactory
    ,IConfiguration configuration
    ,IMapper mapper
    )
{
    this._PostRepository = PostRepository;
    this._unitOfWork = UnitOfWOrk;
    this._configuration = configuration;
    this._mapper = mapper;
    this._Logger = loggerFactory.CreateLogger("AiDaSiBlog.API.Controllers.PostController");
}
[HttpGet]
public async Task<IActionResult> Get(PostParameters postParameters)
{
    var posts = await _PostRepository.GetAllPosts(postParameters);
    var postResources = _mapper.Map<IEnumerable<Post>, IEnumerable<PostResource>>(posts);

    var metta = new {
        Pagesize = posts.PageSize,
        PageIndex = posts.PageIndex,
        TotalItemsCount = posts.TotalItemsCount,
        PageCount = posts.PageCount
    };
    //标准化
    Response.Headers.Add("x-Pagination", JsonConvert.SerializeObject(metta,new JsonSerializerSettings()
    {
        //Json输出格式小写
        ContractResolver = new CamelCasePropertyNamesContractResolver()
    }));
    return Ok(postResources);

结果:


3.生成前后页的Url


首先创建前后页枚举

PaginationResourceUriType.cs

#region 生成前后页的的Url枚举
public enum PaginationResourceUriType
{
    CurrentPage,
    PreviousPage,
    NextPage
}
#endregion

注册服务

#region 生成前后页的的Url枚举
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IUrlHelper>(factory => {
    var actionContext = factory.GetService<IActionContextAccessor>().ActionContext;
    return new UrlHelper(actionContext);
});

#endregion

注入到控制器

private readonly IUrlHelper _urlHelper;
 public PostController(IUnitOfWOrk UnitOfWOrk
     , IPostRepository PostRepository
     ,ILoggerFactory loggerFactory
     ,IConfiguration configuration
     ,IMapper mapper
     , IUrlHelper urlHelper
     )
 {
     this._PostRepository = PostRepository;
     this._unitOfWork = UnitOfWOrk;
     this._configuration = configuration;
     this._mapper = mapper;
     this._urlHelper = urlHelper;
     this._Logger = loggerFactory.CreateLogger("AiDaSiBlog.API.Controllers.PostController");
 }

生成前后页Url

 private string CreatePostUri(PostParameters parameters,PaginationResourceUriType uriType)
 {
     switch (uriType)
     {
         case PaginationResourceUriType.PreviousPage:
             var preiousParameters = new
             {
                 pagesize = parameters.PageSize,
                 pageIndex = parameters.PageIndex-1,
                  orderBy= parameters.OrderBy,
                 fields = parameters.Fields
             };
             return _urlHelper.Link("GetPosts", preiousParameters);
         case PaginationResourceUriType.NextPage:
             var nextParameters = new
             {
                 pagesize = parameters.PageSize,
                 pageIndex = parameters.PageIndex + 1,
                 orderBy = parameters.OrderBy,
                 fields = parameters.Fields
             };
             return _urlHelper.Link("GetPosts", nextParameters);
         default:
             var currentParameters = new
             {
                 pagesize = parameters.PageSize,
                 pageIndex = parameters.PageIndex - 1,
                 orderBy = parameters.OrderBy,
                 fields = parameters.Fields
             };
             return _urlHelper.Link("GetPosts", currentParameters);
     }
 }

控制器代码修改一下

 [HttpGet]
 public async Task<IActionResult> Get(PostParameters postParameters)
 {
     var posts = await _PostRepository.GetAllPosts(postParameters);
     var postResources = _mapper.Map<IEnumerable<Post>, IEnumerable<PostResource>>(posts);

     //判断上一页
     var previousPageLink = posts.HasPrevious ? CreatePostUri(postParameters, PaginationResourceUriType.PreviousPage) : null;
     //判断下一页
     var nextPageLink = posts.HasNext ? CreatePostUri(postParameters, PaginationResourceUriType.NextPage) : null;


     var metta = new {
         Pagesize = posts.PageSize,
         PageIndex = posts.PageIndex,
         TotalItemsCount = posts.TotalItemsCount,
         PageCount = posts.PageCount,
         PreviousPageLink=previousPageLink,
         NextPageLink = nextPageLink
     };
     //标准化
     Response.Headers.Add("x-Pagination", JsonConvert.SerializeObject(metta,new JsonSerializerSettings()
     {
         //Json输出格式小写
         ContractResolver = new CamelCasePropertyNamesContractResolver()
     }));
     return Ok(postResources);
 }

结果(数据都一样就不展示了):


4.搜索

修改PostParameters.cs类,添加Title字段

public class PostParameters: QueryParameters
{
    public string Title { get; set; }
}

修改PostRepository.cs类中GetAllPosts方法(这里我用了等于,大家可以用包含)

public async Task<PaginatedList<Post>> GetAllPosts(PostParameters postParameters)
{
    #region 翻页,排序,查询

    var query = _myContext.Posts.AsQueryable();
    if (!string.IsNullOrEmpty(postParameters.Title))
    {
        var title = postParameters.Title.ToLowerInvariant();
        query = query.Where(x => x.Title.ToLowerInvariant() == title);
    }

    query = query.OrderBy(x => x.Id);
    var count = await query.CountAsync();
    #endregion
    //return await _myContext.Posts.ToListAsync();
    var data = await query
        .Skip(postParameters.PageIndex * postParameters.PageSize)
        .Take(postParameters.PageSize)
        .ToListAsync();
    return new PaginatedList<Post>(postParameters.PageIndex,postParameters.PageSize,count,data);
}


5.排序

这里我们用到 System.Linq.Dynamic.Core 类库

安装:


评价
有钱人的开发有着你们不懂的快乐!O(* ̄︶ ̄*)O
排名
6
文章
6
粉丝
16
评论
8
{{item.ArticleTitle}}
{{item.BlogName}} : {{item.Content}}