前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《ASP.ENT Core 与 RESTful API 开发实战》-- (第6章)-- 读书笔记(上)

《ASP.ENT Core 与 RESTful API 开发实战》-- (第6章)-- 读书笔记(上)

作者头像
郑子铭
发布2021-01-13 15:43:51
4040
发布2021-01-13 15:43:51
举报
文章被收录于专栏:DotNet NB && CloudNative

第 6 章 高级查询和日志

6.1 分页

在 EF Core 中,数据的查询通过集成语言查询(LINQ)实现,它支持强类型,支持对 DbContext 派生类的 DbSet 类型成员进行访问,DbSet 类实现了 IQueryable 和 IEnumerable 接口,LINQ 形式的查询会通过数据库提供程序转换为数据库查询语言,并最终返回实体集合

接下来,在 Library.API 项目中实现分页功能

添加一个 AuthorResourceParameters 类

代码语言:javascript
复制
namespace Library.API.Helpers
{
    public class AuthorResourceParameters
    {
        public const int MaxPageSize = 50;
        private int _pageSize = 10;

        public int PageNumber { get; set; } = 1;

        public int PageSize
        {
            get { return _pageSize; }
            set
            {
                _pageSize = (value > MaxPageSize) ? MaxPageSize : value;
            }
        }
    }
}

修改 GetAuthorsAsync 方法实现分页

代码语言:javascript
复制
[HttpGet]
public async Task<ActionResult<List<AuthorDto>>> GetAuthorsAsync([FromQuery] AuthorResourceParameters parameters)
{
    var authors = (await RepositoryWrapper.Author.GetAllAsync())
        .Skip(parameters.PageSize * (parameters.PageNumber - 1))
        .Take(parameters.PageSize)
        .OrderBy(author => author.Name);
    var authorDtoList = Mapper.Map<IEnumerable<AuthorDto>>(authors);

    return authorDtoList.ToList();
}

完成之后可以请求 URL: http://localhost:5001/api/author?pageNumber=2&pageSize=3

添加分页元数据

首先创建一个分页列表类

代码语言:javascript
复制
namespace Library.API.Helpers
{
    public class PagedList<T> : List<T>
    {
        public int CurrentPage { get; private set; }
        public int TotalPages { get; private set; }
        public int PageSize { get; private set; }
        public int TotalCount { get; private set; }
        public bool HasPrevious => CurrentPage > 1;
        public bool HasNext => CurrentPage < TotalPages;

        public PagedList(List<T> items, int totalCount, int pageNumber, int pageSize)
        {
            TotalCount = totalCount;
            CurrentPage = pageNumber;
            PageSize = pageSize;

            TotalPages = (int) Math.Ceiling((double) totalCount / pageSize);
            AddRange(items);
        }
    }
}

在 IAuthorRepository 添加一个方法

代码语言:javascript
复制
Task<PagedList<Author>> GetAllAsync(AuthorResourceParameters parameters);

在 AuthorRepository 添加实现方法

代码语言:javascript
复制
public async Task<PagedList<Author>> GetAllAsync(AuthorResourceParameters parameters)
        {
            IQueryable<Author> queryableAuthors = DbContext.Set<Author>();

            var totalCount = queryableAuthors.Count();
            var items = queryableAuthors.Skip((parameters.PageNumber - 1) * parameters.PageSize)
                .Take(parameters.PageSize).ToList();

            return new PagedList<Author>(items, totalCount, parameters.PageNumber, parameters.PageSize);
        }

为了使创建 PagedList 的逻辑具有通用性,可以在 PagedList 类中添加一个静态方法 CreateAsync

代码语言:javascript
复制
public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize)
{
    var totalCount = source.Count();
    var items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
    var list = new PagedList<T>(items, totalCount, pageNumber, pageSize);
    return await Task.FromResult(list);
}

在 GetAllAsync 中使用

代码语言:javascript
复制
public Task<PagedList<Author>> GetAllAsync(AuthorResourceParameters parameters)
{
    IQueryable<Author> queryableAuthors = DbContext.Set<Author>();

    //var totalCount = queryableAuthors.Count();
    //var items = queryableAuthors.Skip((parameters.PageNumber - 1) * parameters.PageSize)
    //    .Take(parameters.PageSize).ToList();

    //return new PagedList<Author>(items, totalCount, parameters.PageNumber, parameters.PageSize);

    return PagedList<Author>.CreateAsync(queryableAuthors, parameters.PageNumber, parameters.PageSize);
}

接下来,在 AuthorController 中重构 GetAuthorsAsync 代码

代码语言:javascript
复制
[HttpGet(Name = nameof(GetAuthorsAsync))]
public async Task<ActionResult<List<AuthorDto>>> GetAuthorsAsync([FromQuery] AuthorResourceParameters parameters)
{
    var pagedList = await RepositoryWrapper.Author.GetAllAsync(parameters);
    var paginationMetedata = new
    {
        totalCount = pagedList.TotalCount,
        pageSize = pagedList.PageSize,
        currentPage = pagedList.CurrentPage,
        totalPages = pagedList.TotalPages,
        previousePageLink = pagedList.HasPrevious
            ? Url.Link(nameof(GetAuthorsAsync), new
            {
                pageNumber = pagedList.CurrentPage - 1,
                pageSize = pagedList.PageSize
            })
            : null,
        nextPageLink = pagedList.HasNext
            ? Url.Link(nameof(GetAuthorsAsync), new
            {
                pageNumber = pagedList.CurrentPage + 1,
                pageSize = pagedList.PageSize
            })
            : null
    };

    Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(paginationMetedata));

    //var authors = (await RepositoryWrapper.Author.GetAllAsync())
    //    .Skip(parameters.PageSize * (parameters.PageNumber - 1))
    //    .Take(parameters.PageSize)
    //    .OrderBy(author => author.Name);
    var authorDtoList = Mapper.Map<IEnumerable<AuthorDto>>(pagedList);

    return authorDtoList.ToList();
}

以 Get 方法请求 URL 后,服务器不仅返回所请求的资源,并且在响应的消息头中包含了分页元数据,可以通过 previousePageLink,nextPageLink 的 URL 值直接访问上一页以及下一页数据

6.2 过滤和搜索

过滤,是对资源的一个或多个属性与指定的参数值进行匹配并筛选

通过出生地过滤作者,首先在 AuthorResourceParameters 中添加 BirthPlace 属性

代码语言:javascript
复制
public string BirthPlace { get; set; }

然后,修改 AuthorRepository 的 GetAllAsync 方法

代码语言:javascript
复制
if (!string.IsNullOrWhiteSpace(parameters.BirthPlace))
{
    queryableAuthors = queryableAuthors.Where(m => m.BirthPlace.ToLower() == parameters.BirthPlace);
}

接着,修改 AuthorController 的 GetAuthorsAsync 方法中生成分页数据的代码,添加过滤信息

代码语言:javascript
复制
previousePageLink = pagedList.HasPrevious
    ? Url.Link(nameof(GetAuthorsAsync), new
    {
        pageNumber = pagedList.CurrentPage - 1,
        pageSize = pagedList.PageSize,
        birthPlace = parameters.BirthPlace
    })
    : null,
nextPageLink = pagedList.HasNext
    ? Url.Link(nameof(GetAuthorsAsync), new
    {
        pageNumber = pagedList.CurrentPage + 1,
        pageSize = pagedList.PageSize,
        birthPlace = parameters.BirthPlace
    })
    : null

完成之后可以请求 URL: https://localhost:5001/api/authors?birthplace=beijing&pagesize=2

这样可以看到下一页的 URL 中不仅包含分页参数,也包含过滤参数

搜索功能的实现方式与过滤一样

首先在 AuthorResourceParameters 中添加 SearchQuery 属性

代码语言:javascript
复制
public string SearchQuery { get; set; }

然后,修改 AuthorRepository 的 GetAllAsync 方法

代码语言:javascript
复制
if (!string.IsNullOrWhiteSpace(parameters.SearchQuery))
{
    queryableAuthors = queryableAuthors.Where(m =>
        m.BirthPlace.ToLower().Contains(parameters.SearchQuery.ToLower()) ||
        m.Name.ToLower().Contains(parameters.SearchQuery.ToLower()));
}

接着,修改 AuthorController 的 GetAuthorsAsync 方法中生成分页数据的代码,添加过滤信息

代码语言:javascript
复制
previousePageLink = pagedList.HasPrevious
    ? Url.Link(nameof(GetAuthorsAsync), new
    {
        pageNumber = pagedList.CurrentPage - 1,
        pageSize = pagedList.PageSize,
        birthPlace = parameters.BirthPlace,
        searchQuery = parameters.SearchQuery
    })
    : null,
nextPageLink = pagedList.HasNext
    ? Url.Link(nameof(GetAuthorsAsync), new
    {
        pageNumber = pagedList.CurrentPage + 1,
        pageSize = pagedList.PageSize,
        birthPlace = parameters.BirthPlace,
        searchQuery = parameters.SearchQuery
    })
    : null

完成之后可以请求 URL: https://localhost:5001/api/authors?searchQuery=author&birthplace=beijing&pagesize=2

这样可以看到下一页的 URL 中不仅包含分页参数,也包含过滤参数和查询参数

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第 6 章 高级查询和日志
    • 6.1 分页
      • 6.2 过滤和搜索
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档