学习笔记02:翻页 过滤 排序

1 翻页

Query String  http://localhost:5000/api/posts?pageIndex=2&pageSize=10&orderBy=Id

1.1数据分页

1.建立 QueryParameters.cs 数据分页方法类 包含.pageIndex, pageSize, orderBy 等分页参数 

2.建立PostParameters.cs post专用的分页类,继承自QueryParameters.cs 即可.(无特殊条件可以不用写其他内容,继承功能够用即可)

3.1把PostParameters 传给PostController.cs 的[HttpGet] 如下:
public async Task<IActionResult> Get(PostParameters postParameters)
3.2把postParameters传给PostController.cs具体的实现方法
原来:
var postList = await _postRepository.GetAllPostAsync();
改为:
var postList = await _postRepository.GetAllPostAsync(postParameters);
3.3给接口添加参数
同时修改接口
原来:
Task<PaginatedList<Post>> GetAllPostAsync();
改为:
Task<PaginatedList<Post>> GetAllPostAsync(PostParameters postParameters);
3.4在实现类添加参数 PostParameters postParameters,同时原来的列表方法修改下如下
原来为直接列出列表数据.
return await _myContext.Post.ToListAsync();
改为:
1.按Id排序
var query = _myContext.Post.OrderBy(x => x.Id);

2.数据分页
var data = await query.Skip(postParameters.PageIndex * postParameters.PageSize)
.Take(postParameters.PageSize).ToListAsync();

 1.2分页按钮(不含上一页 下一页) ,定义一个PageList.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 totalItemsCount, IEnumerable<T> data)
        {
            PageIndex = pageIndex;
            PageSize = pageSize;
            TotalItemsCount = totalItemsCount;
            AddRange(data);
        }
    }

修改PostRepository.cs
原返回类型:
public async Task<IEnumerable<Post>> GetAllPostAsync(PostParameters postParameters)
修改为:
public async Task<PaginatedList<Post>> GetAllPostAsync(PostParameters postParameters)
同时修改对应的接口的返回类型.


再修改PostRepository.cs 具体的代码
1.统计出总条数
var count = await query.CountAsync();

2.把原来的返回数据返回给一个变量如 var data
var data = await query.Skip(postParameters.PageIndex * postParameters.PageSize)
.Take(postParameters.PageSize).ToListAsync();

  3.以上信息组合成返回数据

 return new PaginatedList<Post>(postParameters.PageIndex,postParameters.PageSize,count,data);

  4.在PostController创建匿名类 ,并将属性名改成首字母小写.(new部分负责)

var meta = new
            {
                Pagesize = postList.PageSize,
                Pageindex = postList.PageIndex,
                TotalItemsCount = postList.TotalItemsCount,
                PageCount = postList.PageCount
            };

            Response.Headers.Add("x-Pagination",JsonConvert.SerializeObject(meta,new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));

1.3分页 上一页 下一页 

使用IUrlHelper  用之前需要配置 IActionContextAccessor 这个东西,在Controller里写一个自定义的方法返回前一页 后一页.

1.创建一个枚举类PaginationResourceUriType.cs
namespace BlogDemo.Core.Entities { public enum PaginationResourceUriType { CurrentPage, PreviousPage, NextPage } }

2.startup注册IUrlHelper

            //注册UrlHelper
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
            services.AddScoped<IUrlHelper>(factory =>
            {
                var actionContext = factory.GetService<IActionContextAccessor>().ActionContext;
                return new UrlHelper(actionContext);
            });

3.在PostController里添加一个创建Url的方法
        private string CreatePostUri(PostParameters parameters, PaginationResourceUriType uriType)
        {
            switch (uriType)
            {
                case PaginationResourceUriType.PreviousPage:
                    var previousParameters = new
                    {
                        pageIndex = parameters.PageIndex - 1,
                        pageSize = parameters.PageSize,
                        orderBy = parameters.OrderBy,
                        fields = parameters.Fields
                    };
                    return _urlHelper.Link("GetPosts", previousParameters);
                case PaginationResourceUriType.NextPage:
                    var nextParameters = new
                    {
                        pageIndex = parameters.PageIndex + 1,
                        pageSize = parameters.PageSize,
                        orderBy = parameters.OrderBy,
                        fields = parameters.Fields
                    };
                    return _urlHelper.Link("GetPosts", nextParameters);
                default:
                    var currentParameters = new
                    {
                        pageIndex = parameters.PageIndex,
                        pageSize = parameters.PageSize,
                        orderBy = parameters.OrderBy,
                        fields = parameters.Fields
                    };
                    return _urlHelper.Link("GetPosts", currentParameters);
            }
        }

  给[HttpGet]起个名字   [HttpGet(Name = "GetPosts")]  针对这个名字的 Get操作

  4.在匿名类上生成前一页后一页连接,并将生成的  previousPageLink  nextPageLink添加到元数据.

            var previousPageLink = postList.HasPrevious ?
                CreatePostUri(postParameters, PaginationResourceUriType.PreviousPage) : null;

            var nextPageLink = postList.HasNext ?
                CreatePostUri(postParameters, PaginationResourceUriType.NextPage) : null;

调试查看结果

2.过滤  条件应用于Resource Model.

过滤: 对集合资源附加一些条件, 筛选出结果.如: http://localhost:5000/api/countries?englishName=China.
过滤属性可以放在QueryParameters的子类里.


搜索: 使用关键字对集合资源进行模糊搜索.
http://localhost/api/countries?searchTerm=hin

2.1 在PostParameters增加一个Title属性.(Post实体里有)   

 public string Title { get; set; }

2.2 然后在PostRepository进行过滤

原来:
var query = _myContext.Post.OrderBy(x => x.Id);
修改:将query先出集合数据,再排序.中间加上条件判断.
var query = _myContext.Post.AsQueryable(); if (!string.IsNullOrEmpty(postParameters.Title)) { var title = postParameters.Title.ToLowerInvariant(); query = query.Where(x => x.Title.ToLowerInvariant().Contains(title)); } query=query.OrderBy(x => x.Id);

执行调试  如:https://localhost:5001/api/posts?pageindex=0&pagesize=3&title=Post Title 4

 3.排序   在Infrastructure里安装System.Linq.Dynamic.Core

排序思路:建立三层的服务.

第一层 容器层:PropertyMappingContainer   

    PostResource 到 Post他两之间属性有一些映射,我们把它两之间的属性映射算成一对,注册到这个容器.

第二层:他两之间的属性映射PropertyMapping(PostPropertyMapping)

第三次:具体到每个映射的属性MappedProperty

Services文件夹下的cs文件解析,常规的,不需要改变,项目组复制使用即可.

1.1.MappedProperty.cs  Resource和Entity   要求字段要对应:名字(Name) ,           //排序是否是相反的(Revert).

    public class MappedProperty
    {
        public string Name { get; set; }
        public bool Revert { get; set; }
    }

1.2 PropertyMapping.cs 两个表之间的映射关系.

    Resources/PostPropertyMapping.cs 继承PropertyMapping.cs  且实现两表之间的具体映射.

    public class PostPropertyMapping : PropertyMapping<PostResource, Post>
    {
        public PostPropertyMapping() : base(
            new Dictionary<string, List<MappedProperty>>
                (StringComparer.OrdinalIgnoreCase)
                {
                    [nameof(PostResource.Title)] = new List<MappedProperty>
                    {
                        new MappedProperty{ Name = nameof(Post.Title), Revert = false}
                    },
                    [nameof(PostResource.Body)] = new List<MappedProperty>
                    {
                        new MappedProperty{ Name = nameof(Post.Body), Revert = false}
                    },
                    [nameof(PostResource.Author)] = new List<MappedProperty>
                    {
                        new MappedProperty{ Name = nameof(Post.Author), Revert = false}
                    }
                })
        {
        }
    }

1.3使用容器

1.4startup注册

1.5使用排序,在Infrastructure项目建立 Extensions/QueryableExtensions.cs类.

1.6在PostRepository添加 IPropertyMappingContainer构造函数.再修改如下注释的代码

            //query = query.OrderBy(x => x.Id);
            query = query.ApplySort(postParameters.OrderBy, _propertyMappingContainer.Resolve<PostResource, Post>());
原文地址:https://www.cnblogs.com/dxh0535/p/10414071.html