OData武装你的WEBAPI-分页查询

武装你的WEBAPI-OData入门

武装你的WEBAPI-OData便捷查询

武装你的WEBAPI-OData分页查询

武装你的WEBAPI-OData资源更新

武装你的WEBAPI-OData之EDM

武装你的WEBAPI-OData常见问题

武装你的WEBAPI-OData使用Endpoint

Introduction

分页是数据请求避免不了的问题,数据很多的情况下,通过GET请求一次性返回所有的数据,不光性能底下,而且不好展示。

分页的原理就是客户端请求服务器,服务器返回的数据是有限的数据(限制于pageSize),同时返回一个数据的总量count,方便客户端进行处理。也有另外一种实现,使用nextlink指示下一页的位置。

传统实现

传统的实现,我比较喜欢LINQ的Skip和Take方法。

/// <summary> /// 有参GET请求 /// </summary> /// <returns></returns> [HttpGet("page")] [ProducesResponseType(typeof(ReturnData<Page<UserInfoModel>>), Status200OK)] [ProducesResponseType(typeof(ReturnData<string>), Status404NotFound)] public async Task<ActionResult> Get(string username, int pageNo, int pageSize) { if (pageSize <= 0 || pageNo <= 0) return BadRequest(new ReturnData<string>("Error request")); IEnumerable<UserInfoModel> result; if (string.IsNullOrWhiteSpace(username)) result = _userManager.Users.Select(w => ToUserInfoModel(w)).ToList(); else result = _userManager.Users.Select(w => ToUserInfoModel(w)).ToList().Where(w => w.Username.Contains(username)); var response = result.Skip((pageNo - 1) * pageSize).Take(pageSize); Page<UserInfoModel> page = new Page<UserInfoModel>() { PageNo = pageNo, PageSize = pageSize, Result = response, TotalCount = result.Count() }; return Ok(new ReturnData<Page<UserInfoModel>>(page)); }

通过传递username、pageNo和pageSize即可实现分页功能。

OData实现分页

OData查询不需要后端再自行设计接受参数、实现等内容,并且支持两种方式实现分页:客户端模式和服务器模式。首先我们需要补补几个关键字的用法:(适用于OData V4)

$count

count关键字可以随同查询一起使用,使用$count=true的形式即可在查询结果中追加返回符合查询条件的所有的记录的数量。

GET :9000/api/devicedatas('ZW000001')?$count=true

注意这里不是返回的当前结果的计数。

{ "@odata.context": "http://localhost:9000/api/$metadata#DeviceDatas", "@odata.count": 80, "value": [ { "id": "554b1ed8-6429-4ad3-83f9-45c7696547e6", "deviceId": "ZW000001", "timestamp": 1589544960000, "dataArray": [] }, ... $skip

skip关键字可以指定跳过的记录数量,使用$skip=10这种形式。

GET :9000/api/devicedatas('ZW000001')?$skip=30

返回的结果是跳过了前面的N条记录。

$top

top关键字指定截取的符合查询条件中的前n条记录,使用top=10这种形式。

GET :9000/api/devicedatas('ZW000001')?$top=10 $skiptoken

skiptoken这个东西和前面的东西都不一样。skiptoken必须要服务器返回,一般来说是服务器根据主键的形式返回结果,然后调用方直接调用。经常出现在nextlink中,用于服务器分页。

GET :9000/api/devicedatas('ZW000001')?$skiptoken='554b1ed8-6429-4ad3-83f9-45c7696547e6'

注意这里不是返回的当前结果的计数。

{ "@odata.context": "http://localhost:9000/api/$metadata#DeviceDatas", "value": [ { "id": "554b1ed8-6429-4ad3-83f9-45c7696547e6", "deviceId": "ZW000001", "timestamp": 1589544960000, "dataArray": [] }, ... 客户端模式

客户端模式是客户端主导的分页实现,分页的页数数量之类的,都需要由客户端指定,对客户端来说,比较灵活。主要使用到count、skip和top三个关键字。

默认情况,服务器返回所有的记录。

假设按照每页10条记录进行分页,那么我们首次请求(请求第一页)应该使用$count=true&$skip=0&$top=10获取第一页数据,同时带有数据计数。

根据第一次请求获得数据计数,可以快速计算总共的分页数量。比如返回count=72,那么总共的页数应该是72/10 + 1 =8页(最后一页只有2个数据)

生成每个页码的链接,第二页应该是$count=true&$skip=10&$top=10

GET :9000/api/devicedatas('ZW000001')?$count=true&$skip=10&$top=10

这几条命令需要先启用,可以在startup.cs中修改:

app.UseMvc( routeBuilder => { // the following will not work as expected // BUG: https://github.com/OData/WebApi/issues/1837 // routeBuilder.SetDefaultODataOptions( new ODataOptions() { UrlKeyDelimiter = Parentheses } ); routeBuilder.ServiceProvider.GetRequiredService<ODataOptions>().UrlKeyDelimiter = Parentheses; // global odata query options //routeBuilder.EnableDependencyInjection(); routeBuilder.Select().Expand().Filter().OrderBy().MaxTop(600).Count().SkipToken(); routeBuilder.MapVersionedODataRoutes("odata", "api", modelBuilder.GetEdmModels()); }); 服务端模式

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssgxd.html