zoukankan      html  css  js  c++  java
  • 《ASP.ENT Core 与 RESTful API 开发实战》-- (第6章)-- 读书笔记(上)

    第 6 章 高级查询和日志

    6.1 分页

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

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

    添加一个 AuthorResourceParameters 类

    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 方法实现分页

    [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

    添加分页元数据

    首先创建一个分页列表类

    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 添加一个方法

    Task<PagedList<Author>> GetAllAsync(AuthorResourceParameters parameters);
    

    在 AuthorRepository 添加实现方法

    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

    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 中使用

    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 代码

    [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 属性

    public string BirthPlace { get; set; }
    

    然后,修改 AuthorRepository 的 GetAllAsync 方法

    if (!string.IsNullOrWhiteSpace(parameters.BirthPlace))
    {
        queryableAuthors = queryableAuthors.Where(m => m.BirthPlace.ToLower() == parameters.BirthPlace);
    }
    

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

    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 属性

    public string SearchQuery { get; set; }
    

    然后,修改 AuthorRepository 的 GetAllAsync 方法

    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 方法中生成分页数据的代码,添加过滤信息

    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 中不仅包含分页参数,也包含过滤参数和查询参数

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    【结构型】Proxy模式
    【结构型】Flyweight模式
    【结构型】Facade模式
    【结构型】Decorate模式
    【结构型】Composite模式
    适配器模式 -- 大话设计模式
    状态模式 -- 大话设计模式
    抽象工厂模式 -- 大话设计模式
    建造者模式 -- 大话设计模式
    观察者模式 -- 大话设计模式
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/13277178.html
Copyright © 2011-2022 走看看