• [水煮 ASP.NET Web API2 方法论](12-3)OData 查询


    问题

    Web API 怎么支持通用的 OData 系统查询项,例如 $select 或 $filter。

     

    解决方案

    为了在 Web API 中启用查询项,我们需要在 Action 上使用 EnableQueryAttribute。

    如果 Action 没有返回集合,而是返回单个对象的实例,调用端仍然可以使用 $expand 和 $select 两个查询语句,要达到这个目的,我们必须将返回对象包装在 SingleResult<T> 中。集合和单个对象实例作为返回值的例子如订单 12-7 所示

    清单 12-7. 在两个路由上启用查询语句

     1     public class PlayersController : ODataController
     2 
     3     {
     4 
     5         private readonly PlayersContext playersDbContext = new PlayersContext();
     6 
     7         [EnableQuery]
     8 
     9         public IQueryable<Player> GetAllPlayers()
    10 
    11         {
    12 
    13             Return playersDbContext;
    14 
    15         }
    16 
    17         [EnableQuery]
    18 
    19         public SingleResult<Player> GetSinglePlayers(int key)
    20 
    21         {
    22 
    23             return SingleResult.Create(playersDbContext.Where(x => x.Id == key).AsQueryable());
    24 
    25         }
    26 
    27     }

    工作原理

    OData 查询选项是被定义在 OData 规范中,如,查询字符串的参数控制的是返回资源的数量和顺序。ASP.NET Web API 几乎支持所有的标准查询项:

    • $expand:允许响应给客户端的信息包含关联资源(导航属性)
    • $select:限制返回的属性
    • $filter:过滤 Api 暴露出来的资源
    • $count:获取集合中实体的总数
    • $orderby:指定集合的排序 key
    • $skip:获取集合跳过的数量
    • $top:限制集合返回集合的数量
    • $format:请求特定的响应格式

    唯一不支持的是 $search 查询参数。

     

    小提示 可以查看 OData 4.0 支持的完整的文档地址:http://docs.oasis-open.org/OData/new-in-OData/v4.0/cn01/new-in-OData-v4.0-cn01.html

    查询项是在 ASP.NET Web API 中被 ODataQueryOption 类所描述的。EnableQueryAttribute 的工作方式实际是非常简单的。因为他是 Action 的 Filter,在 OnActionExecuted 方法中会获取 Action 的响应,并转换 HttpContent 为ObjectContent<T>。然后根据 HttpRequest 基于客户端的参数构造 ODataQueryOptions 实例,并返回相应的响应给客户端。如果响应是集合的话,可以响应客户端所有的查询项。如果响应不是集合,就会通过 ObjectContent 包装成 SingleResult<T>。这些时候,$expand 和 $select 都是可用的。

    不使用 EnableQueryAttribute,也可以使用 ODataQueryOptions,他是可以接受 Action 的参数的。这种方式是通过自定义 HttpParameterBinding 类型的 ODataQueryParameterBinding 来支持的。我们也可以使用 ODataQueryOptions 实例中的信息手动执行相关查询。

    在 Web API 中我们不需要完全掌握 OData 就可以体会到查询项给我们带来的便利。就算不是基于 ODataCotrollers,只要 Action 上使用了 EnableQueryAttribute 属性标签,我们还是可以在 Web API 上使用一些基础查询项,例如,$top,$skip,$select。

     

    代码演示

    在 Controller 的 Action 上使用 EnableQueryAttribute,这样的请求就可以使用 OData 查询项,如清单 12-7

    • Host/Plays(1)$select=Name,Team:使用 Player 实体的 Id 进行过滤,仅仅返回 Name 和 Team 两个属性。这个例子的响应,如清单 12-8.

     

    清单 12-8. 从 OData 的 Web API 查询响应例子

    {
      "@OData.context":"http://localhost:43539/OData/$metadata#Players(Name,Team)/$entity","Name":"Name1","Team":"Team"
    } 
    • Host/Players?skip=1&$top=2:忽略集合中第一个实体,然后再剩下的实体中获取两个返回(可以理解为分页的第二页数据,每页大小是 2)。具体响应,如清单 12-9 所示。

    清单 12-9. 从 OData 的 Web API 查询响应例子

    {
      "@OData.context":"http://localhost:43539/OData/$metadata#Players","value":[
        {
          "Id":1,"Name":"Name1","Team":"Team"
        },{
          "Id":2,"Name":"Name11","Team":"Team"
        }
      ]
    }
    • Host/Players?$format=application/json;OData.metadata=full&$filter=Team%20eq%20%27Team2%27:请求条件你为 Team 属性值为 Whales,以 json 格式返回 ,包含 OData 元数据的所有信息,包含类型和导航链接。具体响应结果,如清单 12-10 所示
    {
      "@OData.context":"http://localhost:43539/OData/$metadata#Players","value":[
        {
          "@OData.type":"#BoiledCode.WebApi.Recipe.ODataDemo.Models.Player","@OData.id":"http://localhost:43539/OData/Players(3)","@OData.editLink":"http://localhost:43539/OData/Players(3)","Id":3,"Name":"Name2","Team":"Team2"
        },{
          "@OData.type":"#BoiledCode.WebApi.Recipe.ODataDemo.Models.Player","@OData.id":"http://localhost:43539/OData/Players(4)","@OData.editLink":"http://localhost:43539/OData/Players(4)","Id":4,"Name":"Name21","Team":"Team2"
        }
      ]
    }

    就像上面提到的,我们可以通过在 Action 方法中使用 ODataQueryOptions 参数,来手动的实现询项。ODataQueryParameterBinding 会帮我完成将对象传入到 Action 的操作,这样我们就可以 Action 内部提取 OData 相关的查询项了。 

    清单 12-11. 在 Action 中使用 ODataQueryOptions

     1         public IQueryable<Player> GetAllPlayers(ODataQueryOptions queryOptions)
     2 
     3         {
     4 
     5             // 客户端传入的 top 和 skip
     6 
     7             var filtered = db.Players.Skip(queryOptions.Skip.Value);
     8 
     9             if (queryOptions.Top.Value > 0)
    10 
    11             {
    12 
    13                 filtered = filtered.Take(queryOptions.Top.Value);
    14 
    15             }
    16 
    17             return filtered.AsQueryable();
    18 
    19         }

     

  • 相关阅读:
    使用comet架构实现了一个基于网页的视频监控prototype!!!!哇哈哈庆祝一下
    Pixysoft.Framework.Noebe.Datamining 数据挖掘开发实录
    论创业成功!让大家的青春充满着无限美好的回忆
    新年第一篇 数据库备份恢复系统上线的挫折
    .Net FrameWork 4.0中使用EF向数据库插入数据报datatime2类型错误的解决办法
    RoRoWoBlog 开源博客系统介绍
    第一次偶然出现的“System.Data.Entity.dll”类型的异常
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    我也来说说Entity Frame Work 4中的数据库优先和代码优先两种方式(2)
    Asp.net MVC 2 + Castle + NHibernate 项目实战(1)
  • 原文地址:https://www.cnblogs.com/shuizhucode/p/6087772.html
Copyright © 2020-2023  润新知