让Web API支持OData查询

时间:2022-08-08 19:34:17

前言

  OData 这词也算是目前热门的词汇之一,而在 ASP.NET Web API 中也支持了 OData 查询服务,本篇就来看看如何在 Web API 中加入 OData 来进行操作。

OData 为何?

  OData 全名 Open Data Protocol (开放数据协议),是由微软所提出的协议,主要目的在于透过 HTTP 服务提供 CRUD 的存取服务,最早出现于 WCF Data Service 中,当 Web API 推出时也提供支持 OData 协议,OData 协议建构在 RESTful 服务上,透过公开的 URI 位置进行操作,例如以下的一个 URI 位置范例:

http://localhost:49988/api/products?$top=1

 
  上面网址中 $top 就是 OData 协议中的一个指令,可以发现使用 OData 的操作方式就是在原本的 URI 位置后附加相对应要操作的指令,以下列出常用的 OData 指令:

$top:同 T-SQL 的 TOP,指定取得数据的前几笔。
$orderby:同 T-SQL 的 ORDER BY,可指定想排序的字段。
$skip:略过的笔数,可用于数据分页查询。
$filter:过滤条件,额外区分 eg (等于)、ne (不等于) 、lt (小于)、le (小于等于)、gt (大于)、ge (大于等于)。
 

  上方列出的是常用的指令,当然,因为 OData 还在继续发展中,所以日后可能将提供更多的指令可以使用,在使用 OData 指令时需要注意指令都需要包含「$」符号,且当如果有多个指令需要串接时,可以使用「&」符号进行串接,例如: /api/products?$top=1&$orderby=Id 。

  在 Web API 中透过了使用 OData 的帮助,能够让开发者在开发时期专心于数据处理与逻辑的撰写,能先不考虑因使用者的需求而需要进行某些排序、筛选的问题,开发人员也不必因特定需求而要多撰写对应方法,只需要最后透过 OData 指令就能够很有弹性的筛选出目标数据。

实作 OData

  首先提醒一点,如果要在 .Net Framework 4.0 上使用 OData,需要额外安装 OData 扩充组件,我们可以透过使用 NuGet 来安装 OData 组件,如下:

 让Web API支持OData查询
 

  接下来使用前几篇所建立的范例程序代码,先来看一段程序代码,以下是未使用 OData 的取得产品数据方法:

 

view sourceprint?1.public IEnumerable<Product> GetAllProducts()2.{3.IEnumerable<Product> products = new ProductDao().GetProducts();4.if (products.FirstOrDefault<Product>() != null)5.return products;6.else7.throw new HttpResponseException(HttpStatusCode.NotFound);8.}

  接着如果我们要让这个取得产品数据的方法变成能够支持 OData 时该如何处理呢? 我们只要稍微改变一下它,看到此方法回传的型别为 IEnumerable<T> 型别,在使用 OData 时需要将 IEnumerable<T> 型别置换成 IQueryable<T> 型别,为何要使用 IQueryable<T> 而不使用 IEnumerable<T> ?

 www.it165.net

  IQueryable 与 IEnumerable 都是在去执行例如 Count() 方法实际产生列取时才会开始产生 SQL 语法捞取数据,但其实两者执行时是有差异的,IEnumerable 在建立其列举时其 SQL 语法就已经固定不变了,如后续再针对此 IEnumerable 附加额外的查询条件时 SQL 语法也不会变更,附加的查询则是将数据捞取出来后才在内存内再做塞选,而 IQueryable 呢? 参考 MSDN 文件中可以发现 IQueryable 多了一个 IQueryProvider 接口,IQueryProvider 能够保存列举前额外增加的查询条件并变动最终执行的 SQL 语法,如对于实际要去数据库捞取数据时差异就会显现,如 LINQ to SQL、Entity Framework,详情可参考黑大的 关于IQueryable<T>特性的小实验 文章。

 

  修改回传 IEnumerable<T> 型别改成 IQueryable<T> 型别后还需要记得在 GetProducts() 方法时加入 AsQueryable<Product> 进行转换,最后在方法加上 [Queryable] 属性,如下:

 

view sourceprint?01.[Queryable]02.public IQueryable<Product> GetAllProducts()03.{04.IQueryable<Product> products =05.new ProductDao().GetProducts().AsQueryable<Product>();06.if (products.FirstOrDefault<Product>() != null)07.return products;08.else09.throw new HttpResponseException(HttpStatusCode.NotFound);10.}

  以上修改完成后,我们就能开始测试看看使用 OData 的效果,如下:

 取得第一笔资料

让Web API支持OData查询
 
使用 Price 排序
 
让Web API支持OData查询
 
略过第 1 笔并使用 Price 排序
 
让Web API支持OData查询
 
 查询分类为 MVC 且 ID 为 1
让Web API支持OData查询

  如此就完成使用 OData 协议的查询功能了,另外如果需要针对 JSON 返回的数据把一些字段隐藏起来的话,可以加入 System.Runtime.Serialization 组件参考,加入后在 Entity Class 的公开属性上加入 [IgnoreDataMember] 属性,如下:

view sourceprint?01.public class Product02.{03.public int Id { getset; }04.public string Name { getset; }05.public string Category { getset; }06.public string Price { getset; }07.[IgnoreDataMember]08.public int Stock { getset; }09.}

  这样回传的 JSON 数据就看不到该字段了,如下:

 让Web API支持OData查询

提供的服务内容如下所示 (提供了一个WagerInformations)

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<service xml:base="http://localhost:9527/ODataService.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2007/app">
<workspace>
<atom:title>Default</atom:title>
<collection href="WagerInformations">
<atom:title>WagerInformations</atom:title>
</collection>
</workspace>
</service>
1.基础查询

  1)列出所有的WagerInformations

    http://localhost:9527/ODataService.svc/WagerInformations

  2)按照主键查询

    http://localhost:9527/ODataService.svc/WagerInformations(1)

     PS:在.net里面一般使用DataServiceKeyAttribute标识主键

  3)获取某个对象的一个成员

    http://localhost:9527/ODataService.svc/WagerInformations(1)/EventName

    获取主键为1的WagerInformations的EventName属性

  4)如果这个属性还有属性 那么依此类推

    http://localhost:9527/ODataService.svc/WagerInformations(1)/Event/EventDateTime

    另外不要试图获取原始类型的一些属性 - -# 例如返回 String的Length属性

  5) $value 方案3返回对象的一个成员用的是Xml的数据格式.实际上我们很多时候不需要那么多的标签,只想拿返回值

    那么使用url http://localhost:9527/ODataService.svc/WagerInformations(1)/EventName/$value

    方案3的数据 <?xml version="1.0" encoding="utf-8" standalone="yes"?><EventName xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices">test 1</EventName>

    方案5的数据 test 1

  6) $filter  条件表达式

    查询EventName 等于 "test 1" 的表达式如下

    http://localhost:9527/ODataService.svc/WagerInformations?$filter=EventName  eq 'test 1'

    查询时间:

    http://localhost:9527/ODataService.svc/WagerInformations?$filter=EventDateTime eq DateTime'2010-12-21T10:10:19.390625'

     组合查询表达式: and操作

    http://localhost:9527/ODataService.svc/WagerInformations?$filter=(EventDateTime eq DateTime'2010-12-21T10:10:19.390625' ) and (BusinessUnitCode eq '2')

  

 

以下是运算符列表 

Operator

Description

C#         equivalent

eq

equals

==

ne

not equal

!=

gt

greater than

>

ge

greater than or equal

>=

lt

less than

<

le

less than or equal

<=

and

and

&&

or

or

||

()

grouping

()

 

 

原文地址:http://blogs.msdn.com/b/alexj/archive/2009/11/18/tip-44-how-to-navigate-an-odata-compliant-service.aspx