客户端模式灵活,但是有一个问题不好处理:客户端在两次请求的过程中,数据发生了变化,那会遇到一些意想不到的问题,比如说数据删除了其中的一些,那么某条数据很有可能会同时出现在两个页。因此,可以让服务器帮我们做分页,服务器管理所有的数据,对两次请求的数据变化也能及时感知,不会出现这个问题。
服务端模式需要使用到skiptoken和pagesize设置。
服务端模式,客户端请求集合,服务器返回部分数据,同时提供一个nextlink,客户端直接请求这个链接,就可以获得更多的数据。
skiptoken启用可以参考上面客户端模式的代码。pagesize是服务器最多每页返回多少条数据的设置,可以在上面全局指定,也可以在具体的方法上面指定。
[ODataRoute] [EnableQuery(PageSize = 1)] [ProducesResponseType(typeof(ODataValue<IEnumerable<DeviceInfo>>), Status200OK)] public IActionResult Get() { return Ok(_context.DeviceInfoes.AsQueryable()); }试着使用原始的方式进行请求。
GET :9000/api/DeviceInfoes?$count=true返回结果如下,能看到,返回的数据的结尾,多了一个@odata.nextLink,这个直接点击,就可以直接请求下一组数据。在下一组数据中又会有在下一组数据的地址,直到最后一组数据。
{ "@odata.context": "http://localhost:9000/api/$metadata#DeviceInfoes", "@odata.count": 3, "value": [ { "deviceId": "ZW000001", "name": null, "deviceType": null, "imagePath": null, "layout": [] } ], "@odata.nextLink": "http://localhost:9000/api/DeviceInfoes?$count=true&$skiptoken=deviceId-'ZW000001'" }注意:
我这里主键使用的是字符串类型,并且用的是EF CORE 3.0,直接请求会返回服务器错误,需要自行指定string的比较模式,可以使用AsEnumerable()在System.Linq中处理。如果使用的主键是数值型,那么应该不会有这个问题。
可以在请求中同时应用skip等客户端模式的语法,构造自己需要的数据。
看完服务器模式,感觉这模式有点僵硬啊,只能一条一条地获取下一个链接,我要直接跳几页的时候怎么办呢?
首先你需要了解分页的模式,我们请求返回的nextlink会是这样子的:
"@odata.nextLink": "https://services.odata.org/V4/TripPinService/People?%24skiptoken=8"我这里使用到了官方提供的一个地址,返回了8条数据,同时指示了下一个链接的位置,很明显,这个skiptoken=8是从第9个开始的,因此指定的只是一个开头的地址,我们可以自行修改成其他数字。(前面说到skiptoken必须要服务生成,指的是后面的查询模式需要是由服务器生成。)
那么对于第三页就是skiptoken=16。但是由于服务器指定了分页的大小8,我们查询还是不方便,可以通过继承EnableQueryAttribute实现,将这个[MyEnableQueryAttribute]替代刚刚的[EnableQuery]。搬运
public class MyEnableQueryAttribute : EnableQueryAttribute { public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions) { int pagesize = xxx; var result = queryOptions.ApplyTo(queryable, new ODataQuerySettings { PageSize = pagesize }); return result; } } 总结OData使用客户端模式的分页和服务端的分页都能够很方便地实现分页查询。一个GET查询全部搞定,梭哈!不要问就是梭!
参考资料https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-odata/965a7cb1-663e-4eef-b9f6-388c7e5c9444?redirectedfrom=MSDN