武装你的WEBAPI-OData便捷查询
本文属于OData系列
目录
- 武装你的WEBAPI-OData入门
- 武装你的WEBAPI-OData便捷查询
- 武装你的WEBAPI-OData分页查询
- 武装你的WEBAPI-OData资源更新
- 武装你的WEBAPI-OData之EDM
- 武装你的WEBAPI-OData常见问题
- 武装你的WEBAPI-OData使用Endpoint
Introduction
前文大概介绍了下OData,本文介绍下它强大便捷的查询。(后面的介绍都基于最新的OData V4)
假设现在有这么两个实体类,并按照前文建立了OData配置。
public class DeviceInfo
{
[Key]
[MaxLength(200)]
public string DeviceId { get; set; }
//....//
public float Longitude { get; set; }
public Config[] Layout { get; set; }
}
public class AlarmInfo
{
[Key]
[MaxLength(200)]
public string Id { get; set; }
public string DeviceId { get; set; }
public string Type { get; set; }
[ForeignKey("DeviceId")]
public virtual DeviceInfo DeviceInfo { get; set; }
public bool Handled { get; set; }
public long Timestamp { get; set; }
}
Controller设置如下,很简单,核心就几行:
[ODataRoute]
[EnableQuery]
[ProducesResponseType(typeof(ODataValue<IEnumerable<DeviceInfo>>), Status200OK)]
public IActionResult Get()
{
return Ok(_context.DeviceInfoes.AsQueryable());
}
[ODataRoute("({key})")]
[EnableQuery]
[ProducesResponseType(typeof(ODataValue<IDeviceInfo>), Status200OK)]
public IActionResult GetSingle([FromODataUri] string key)
{
var result = _context.DeviceInfoes.Find(key);
if (result == null) return NotFound(new ODataError() { ErrorCode = "404", Message = "Cannnot find key." });
return Ok(result);
}
集合与单对象
使用OData,可以很简单的访问集合与单个对象。
//访问集合
GET http://localhost:9000/api/DeviceInfoes
//访问单个对象,注意string类型需要用单引号。
GET http://localhost:9000/api/DeviceInfoes('device123')
$Filter
请求集合很多,我们需要使用到查询来筛选数据,注意,这个查询是在服务器端执行的。
//查询特定设备在一个时间的数据,注意这里需要手动处理一下这个ID为deviceid。
GET http://localhost:9000/api/AlarmInfoes('device123')?$filter=(TimeStamp ge 12421552) and (TimeStamp le 31562346785561)
$Filter支持很多种语法,可以让数据筛选按照调用方的意图进行自由组合,极大地提升了API的灵活性。
$Expand
在查询alarminfo的时候,我很需要API能够返回所有信息,其中包括对应的deviceinfo信息。但是标准的返回是这样的:
{
"@odata.context": "http://localhost:9000/api/$metadata#AlarmInfoes",
"value": [
{
"id": "235314",
"deviceId": "123",
"type": "低温",
"handled": true,
"timestamp": 1589235890047
},
{
"id": "6d2d3af3-2cf7-447e-822f-aab4634b3a13",
"deviceId": "5s3",
"type": null,
"handled": true,
"timestamp": 0
}]
}
只有一个干巴巴的deviceid,要实现展示所有信息的功能,就只能再从deviceinfo的API请求一次,获取对应ID的devceinfo信息。
这就是所谓的N+1问题:请求具有子集的列表时,需要请求1次集合+请求N个集合内数据的具体内容。会造成查询效率的降低。
不爽是不是?看下OData怎么做。请求如下:
GET http://localhost:9000/api/alarminfoes?$expand=deviceinfo
通过指定expand参数,就可以在返回中追加导航属性(navigation property)的信息。
本例中是使用的外键实现的。
{
"@odata.context": "http://localhost:9000/api/$metadata#AlarmInfoes(deviceInfo())",
"value": [
{
"id": "235314",
"deviceId": "123",
"type": "低温",
"handled": true,
"timestamp": 1589235890047,
"deviceInfo": {
"deviceId": "123",
"name": null,
"deviceType": null,
"location": "plex",
"description": "99",
"longitude": 99,
"layout": []
}
}
层级查询
实现了展开之后,那能否查询在多个层级内的数据呢?也可以,考虑查询所有longitude大于90的alarmtype。
GET http://localhost:9000/api/alarminfoes?$expand=deviceinfo&$filter=deviceinfo/longitude gt 90
注意,这里表示层级不是使用
.
而是使用的/
。如果使用.
容易被浏览器误识别,需要特别配置一下。
结果如下:
{
"@odata.context": "http://localhost:9000/api/$metadata#AlarmInfoes(deviceInfo())",
"value": [
{
"id": "235314",
"deviceId": "123",
"type": "低温",
"handled": true,
"timestamp": 1589235890047,
"deviceInfo": {
"deviceId": "123",
"name": null,
"deviceType": null,
"location": "plex",
"description": "99",
"longitude": 99,
"layout": []
}
}
any/all
可以使用any/all来执行对集合的判断。
这个参考:
GET http://services.odata.org/V4/TripPinService/People?$filter=Emails/any(e: endswith(e, 'contoso.com'))
对于我的例子,我使用
GET http://localhost:9000/api/DeviceInfoes?$filter=layout/any(e: e/description eq '0')
服务器会弹出500服务器错误,提示:
System.InvalidOperationException: The LINQ expression 'DbSet<DeviceInfo>
.Where(d => d.Layout
.Any(e => e.Description.Contains(__TypedProperty_0)))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
查看文档之后,原来是我数据的层级比较深了,不在顶级层级类型的查询,在EF Core3.0的版本之前是支持的,在3.0以后就不支持了,主要是怕服务器内存溢出。如果真的要支持,那么就使用AsEnumerable()
去实现客户端查询。
datetime相关
有同学已经注意到了,我这边使用的timestamp的格式是unix形式的时间戳,而没有使用到js常用的ISO8601格式(2004-05-03T17:30:08+08:00
)。如果需要使用到这种时间怎么办?
OData提供了一个语法,使用(datetime'2016-10-01T00:00:00')
这种形式来表示Datetime,这样就能够实现基于datetime的查询。
查询顺序
谓词会使用以下的顺序:$filter, $inlinecount(在V4中已经替换为$count), $orderby, $skiptoken, $skip, $top, $expand, $select, $format。
filter总时最优先的,随后就是count,因此查询返回的count总是符合要求的所有数据的计数。
范例学习
官方有一个查询的Service,可以参考学习和试用,给了很多POSTMAN的示例。
不过有一些略坑的是,有的内容比如Paging里面,加入$count的返回是错的。
前端指南
查询的方法这么复杂,如果手动去拼接query string还是有点虚的,好在有很多库可以帮助我们做这个。
官方提供了各种语言的Client和Server的库:https://www.odata.org/libraries/
前端比较常用的有o.js
const response = await o('http://my.url')
.get('User')
.query({$filter: `UserName eq 'foobar'`});
console.log(response); // If one -> the exact user, otherwise an array of users
这样可以免去拼请求字符串的烦恼,关于o.js
的详细介绍,可以看这里。
参考资料
武装你的WEBAPI-OData便捷查询的更多相关文章
- AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔)
AspNet.WebAPI.OData.ODataPQ 这是针对 Asp.net WebAPI OData 协议下,查询分页.或者是说 本人在使用Asp.Net webAPI 做服务接口时写的一个分页 ...
- AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔)(转)
出处:http://www.bubuko.com/infodetail-827612.html AspNet.WebAPI.OData.ODataPQ 这是针对 Asp.net WebAPI ODat ...
- OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service & Client
一.概念介绍 1.1,什么是OData? 还是看OData官网的简单说明: An open protocol to allow the creation and consumption of quer ...
- AspNet WebApi OData 学习
OData介绍:是一个查询和更新数据的Web协议.OData应用了web技术如HTTP.Atom发布协议(AtomPub)和JSON等来提供对不同应用程序,服务 和存储的信息访问.除了提供一些基本的操 ...
- AspNet.WebAPI.OData.ODataPQ
AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务 AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔) AspNet. ...
- [转]OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service & Client
本文转自:http://www.cnblogs.com/bluedoctor/p/4384659.html 一.概念介绍 1.1,什么是OData? 还是看OData官网的简单说明: An open ...
- 主攻ASP.NET MVC4.0之重生:Asp.Net MVC WebApi OData
1.新建MVC项目,安装OData Install-Package Microsoft.AspNet.WebApi.OData -Version 4.0.0 2.新建WebAPI Controller ...
- [转]Composite Keys With WebApi OData
本文转自:http://chris.eldredge.io/blog/2014/04/24/Composite-Keys/ In our basic configuration we told the ...
- Beautiful Soup 4 方法便捷查询
目录 BS4便捷查询 属性 子节点 父节点 兄弟节点 格式化输出 搜索文档树 修改文档树 BS4便捷查询 准备 : import requests, re from bs4 import Beauti ...
随机推荐
- Xshell 设置右键粘贴即是复制
打开工具->选项->键盘和鼠标面板 1.鼠标部分的右击设置"粘贴剪切板的内容". 2.选择部分,在"自动将所选文本复制到剪切板"前打勾
- 详解 TreeMap
(有关Map集合的基本性质,请观看本人博文-- <详解 Map集合>) TreeMap: 特点: TreeMap 键不允许插入null 键的底层数据结构是红黑树,可保证键的排序和唯一性 线 ...
- linux CVE-2019-13272 本地特权漏洞
漏洞描述 在5.1.17之前的Linux内核中,kernel / ptrace.c中的ptrace_link错误地处理了想要创建ptrace关系的进程的凭据记录,这允许本地用户通过利用父子的某些方案来 ...
- 详解PHP反序列化中的字符逃逸
首发先知社区,https://xz.aliyun.com/t/6718/ PHP 反序列化字符逃逸 下述所有测试均在 php 7.1.13 nts 下完成 先说几个特性,PHP 在反序列化时,对类中不 ...
- Python 七步捉虫法
了解一些技巧助你减少代码查错时间. -- Maria Mckinley 在周五的下午三点钟(为什么是这个时间?因为事情总会在周五下午三点钟发生),你收到一条通知,客户发现你的软件出现一个错误.在有了初 ...
- 移动(appium)自动化测试-爬虫的另一种手段
appium自动化测试环境搭建: 1.Python环境(推荐2.7)和jdk. 2.Adb工具的下载:自己单独下载adb.夜神模拟器自带和Android sdk 3.Apk安装介质:真机.Androi ...
- .NET Core 3 WPF MVVM框架 Prism系列之对话框服务
本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的对话框服务,这也是prism系列的最后一篇完结文章,下面是Prism系列文章的索引: .NET Core 3 WPF MVVM框 ...
- 记使用STL与unique_ptr造成的事故-段子类比
最近由于业务需要在写内存池子时遇到了一个doule-free的问题.折腾半个晚上以为自己的眼睛花了.开始以为是编译器有问题(我也是够自信的),但是在windows下使用qtcreator vs2017 ...
- kubernetes1.30集群部署+dashboard+heapster
v2.1 1.系统配置 1.1.禁用防火墙.禁用selinux #防火墙禁用 systemctl stop firewalld systemctl disable firewalld #SELinux ...
- I/O多路复用之select,poll,epoll简介
一.select 1.起源 select最早于1983年出现在4.2BSD中(BSD是早期的UNIX版本的分支). 它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回 ...