[转]Web API OData V4 Keys, Composite Keys and Functions Part 11
本文转自:https://damienbod.com/2014/09/12/web-api-odata-v4-keys-composite-keys-and-functions-part-11/
Web API OData V4 Keys, Composite Keys and Functions Part 11
This article demonstrates how OData Functions can be used together with entities which have simple keys, composite keys, entity collections or used as plain simple global functions.
Part 1 Getting started with Web API and OData V4 Part 1.
Part 2 Web API and OData V4 Queries, Functions and Attribute Routing Part 2
Part 3Web API and OData V4 CRUD and Actions Part 3
Part 4 Web API OData V4 Using enum with Functions and Entities Part 4
Part 5 Web API OData V4 Using Unity IoC, SQLite with EF6 and OData Model Aliasing Part 5
Part 6 Web API OData V4 Using Contained Models Part 6
Part 7 Web API OData V4 Using a Singleton Part 7
Part 8 Web API OData V4 Using an OData T4 generated client Part 8
Part 9 Web API OData V4 Caching Part 9
Part 10 Web API OData V4 Batching Part 10
Part 11 Web API OData V4 Keys, Composite Keys and Functions Part 11
Code: https://github.com/damienbod/WebApiODataFunctionsAndKeys
Basic Model and Entities
To demonstrate the different functions, with the different model types, a simple OData model is used with 2 Entities, a Stadium entity and a City entity. A namespace ‘D’ is defined because functions require a namespace. If not defined, the ‘Default’ namespace is used. I would prefer to use no namespace in the URL but this is not possible.
- public static IEdmModel GetModel()
- {
- ODataModelBuilder builder = new ODataConventionModelBuilder();
- builder.Namespace = "D";
- builder.ContainerName = "Default";
- EntitySetConfiguration<City> cities = builder.EntitySet<City>("City");
- EntitySetConfiguration<Stadium> stadiums = builder.EntitySet<Stadium>("Stadium");
The City entity has just a simple key property. This is the normal form.
- [DataContract(Name = "City")]
- public class City
- {
- [DataMember]
- [Key]
- public int Id { get; set; }
- [DataMember]
- public long Population { get; set; }
- [DataMember]
- public string Country { get; set; }
- }
The Stadium entity has a composite key made up of 2 key properties.
- [DataContract(Name = "Stadium")]
- public class Stadium
- {
- [DataMember]
- [Key]
- public string Name { get; set; }
- [DataMember]
- [Key]
- public string Country { get; set; }
- [DataMember]
- public int Capacity { get; set; }
- [DataMember]
- public string Owner { get; set; }
- }
Web Configuration for IIS
The web.config needs some special configuration, if you want that the function URLs are reachable in the IIS. If not configured, you receive 404 for your URLs because the ‘.’ is not evaluated. The runAllManagedModulesForAllRequests is set to true.
- <system.webServer>
- <modules runAllManagedModulesForAllRequests="true"></modules>
- <handlers>
- <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
- <remove name="OPTIONSVerbHandler" />
- <remove name="TRACEVerbHandler" />
- <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
- </handlers>
- </system.webServer>
OData Global Functions
These functions are the most simple of all the OData functions to setup. The functions are global and not connected to any entity or collection of entities. The global functions can be added directly to the model builder.
- builder.Function("GlobalFunction")
- .ReturnsCollectionFromEntitySet<Stadium>("Stadium");
The global functions can then be made public inside any ODataController, the route must match the OData routes. This can be checked using the ~/odata/$metadata URL.
- using System.Collections.Generic;
- using System.Web.Http;
- using System.Web.OData;
- using System.Web.OData.Query;
- using System.Web.OData.Routing;
- using WebAPIODataKeys.Models;
- namespace WebApiODataKeys.Controllers
- {
- public class GlobalOdataFunctionsActionsController : ODataController
- {
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("GlobalFunction()")]
- [HttpGet]
- public IHttpActionResult GlobalFunction()
- {
- return Ok(new List<Stadium>{ new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "Global Owner" } });
- }
- }
- }
~/odata/GlobalFunction()
Collection Function which returns a Collection
OData functions can also be added to collections of entities. The following model configuration adds a GetStadiumsWithFunction function to the Stadium entity collection and returns a collection of stadium entities.
- FunctionConfiguration getStadiumsWithFunction = stadiums.EntityType.Collection.Function("GetStadiumsWithFunction");
- getStadiumsWithFunction.ReturnsCollectionFromEntitySet<Stadium>("Stadium");
The function is then made public in the Stadium ODataController. The URL contains the function namespace.
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("D.GetStadiumsWithFunction()")]
- [HttpGet]
- public IHttpActionResult GetStadiumsWithFunction()
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "FC Zug" } });
- }
The function can then be used as follows:
~/odata/Stadium/D.GetStadiumsWithFunction()
Collection Function which returns an Entity
This is very similar to the previous functions except this function has 2 input parameters and returns a single Stadium entity.
Function definition in the model:
- // http://localhost:60096/odata/Stadium/D.GetStadiumTest(test='ddd', land='ssss')
- FunctionConfiguration getStadiumsTest = stadiums.EntityType.Collection.Function("GetStadiumTest");
- getStadiumsTest.Parameter<string>("test");
- getStadiumsTest.Parameter<string>("name");
- getStadiumsTest.ReturnsFromEntitySet<Stadium>("Stadium");
Function definition in the controller:
- // http://localhost:60096/odata/Stadium/D.GetStadiumTest(test='ddd', land='ssss')
- [ODataRoute("D.GetStadiumTest(test={test}, name={name})")]
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [HttpGet]
- public IHttpActionResult GetStadiumTest([FromODataUri] string test, [FromODataUri] string name)
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = name, Name = test, Owner = "FC Zug" } });
- }
~/odata/Stadium/D.GetStadiumTest(test=’ddd’, land=’ssss’)
Entity Get with single key Entity
Before a function can be returned for a single entity, we need to know how to return the single entity in the controller. The key word can be used to match the single key property.
- public IHttpActionResult Get(int key)
- {
- return Ok(new City { Population = 9000000, Country = "Berlin", Id = key });
- }
This can then be used as follows:
~/odata/City(8)
Entity Function (Single key property)
The following example shows how to map a function to a single entity from type City. The function returns a Stadium entity.
- FunctionConfiguration getStadiumFromCityWithFunction = cities.EntityType.Function("GetStadiumsFromCityWithFunction");
- getStadiumFromCityWithFunction.ReturnsCollectionFromEntitySet<Stadium>("Stadium");
The function is added to the city controller, namespace included.
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("City({key})/D.GetStadiumsFromCityWithFunction()")]
- [HttpGet]
- public IHttpActionResult GetStadiumsFromCityWithFunction(int key)
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "FC Zug" } });
- }
The function can be called as follows:
~/odata/City(8)/D.GetStadiumsFromCityWithFunction()
Entity Get with Composite keys Entity
The following controller method shows how to GET the composite Key entity. The key word cannot be used here because it has 2 separate key properties. The key properties have to be defined in the URL.
- // http://localhost:60096/odata/Stadium(Name='Baz', Country='Germany')
- [ODataRoute("(Name={name}, Country={country})")]
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [HttpGet]
- public IHttpActionResult Get([FromODataUri] string name, [FromODataUri] string country)
- {
- return Ok(new Stadium { Capacity = 2300, Country = country, Name = name, Owner = "FC Zug" });
- }
This can be called as follows:
~/odata/Stadium(Name=’Baz’, Country=’Germany’)
Entity Function with Composite keys Entity
Now that we know how to return a single entity for a composite entity, we can add a function to this and use it. The following method adds a function to the composite key entity Stadium.
- FunctionConfiguration getCityFromStadiumWithFunction = stadiums.EntityType.Function("GetCityFromStadiumWithFunction");
- getCityFromStadiumWithFunction.ReturnsFromEntitySet<City>("City");
This is then used in the Stadium ODataController.
- // http://localhost:60096/odata/Stadium(Name='Baz', Country='Germany')/D.GetCityFromStadiumWithFunction()
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("(Name={name},Country={country})/D.GetCityFromStadiumWithFunction()")]
- [HttpGet]
- public IHttpActionResult GetCityFromStadiumWithFunction([FromODataUri] string name, [FromODataUri] string country)
- {
- return Ok(new City { Population = 9000000, Country = "Berlin", Id = 8 });
- }
This can then be called:
~/odata/Stadium(Name=’Baz’, Country=’Germany’)/D.GetCityFromStadiumWithFunction()
The full code example can be download with this link.
As you can see, OData Functions are very easy to use once you understand the design constraints and how the routing works.
Complete OData Model
- public static IEdmModel GetModel()
- {
- ODataModelBuilder builder = new ODataConventionModelBuilder();
- builder.Namespace = "D";
- builder.ContainerName = "Default";
- EntitySetConfiguration<City> cities = builder.EntitySet<City>("City");
- EntitySetConfiguration<Stadium> stadiums = builder.EntitySet<Stadium>("Stadium");
- // Per Collection Stadium
- FunctionConfiguration getStadiumsWithFunction = stadiums.EntityType.Collection.Function("GetStadiumsWithFunction");
- getStadiumsWithFunction.ReturnsCollectionFromEntitySet<Stadium>("Stadium");
- // Per Collection Stadium, returns single entity
- FunctionConfiguration getStadiumsTest = stadiums.EntityType.Collection.Function("GetStadiumTest");
- getStadiumsTest.Parameter<string>("test");
- getStadiumsTest.Parameter<string>("name");
- getStadiumsTest.ReturnsFromEntitySet<Stadium>("Stadium");
- // Per Entity (Single key property) City
- FunctionConfiguration getStadiumFromCityWithFunction = cities.EntityType.Function("GetStadiumsFromCityWithFunction");
- getStadiumFromCityWithFunction.ReturnsCollectionFromEntitySet<Stadium>("Stadium");
- // Per Entity composite key Stadium
- FunctionConfiguration getCityFromStadiumWithFunction = stadiums.EntityType.Function("GetCityFromStadiumWithFunction");
- getCityFromStadiumWithFunction.ReturnsFromEntitySet<City>("City");
- // Global Function
- builder.Function("GlobalFunction").ReturnsCollectionFromEntitySet<Stadium>("Stadium");
- return builder.GetEdmModel();
- }
Complete OData StadiumController
- using System.Collections.Generic;
- using System.Web.Http;
- using System.Web.OData;
- using System.Web.OData.Query;
- using System.Web.OData.Routing;
- using WebAPIODataKeys.Models;
- namespace WebApiODataKeys.Controllers
- {
- [ODataRoutePrefix("Stadium")]
- public class StadiumController : ODataController
- {
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [HttpGet]
- [ODataRoute]
- public IHttpActionResult Get()
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "FC Zug" } });
- }
- // GET odata/stadium?name=fds&country=Switzerland
- //[EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- //[HttpGet]
- //public IHttpActionResult Get(string name, string country)
- //{
- // return Ok(new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "FC Zug" });
- //}
- // http://localhost:60096/odata/Stadium(Name='Baz', Country='Germany')
- [ODataRoute("(Name={name}, Country={country})")]
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [HttpGet]
- public IHttpActionResult Get([FromODataUri] string name, [FromODataUri] string country)
- {
- return Ok(new Stadium { Capacity = 2300, Country = country, Name = name, Owner = "FC Zug" });
- }
- // http://localhost:60096/odata/Stadium/D.GetStadiumTest(test='ddd', land='ssss')
- [ODataRoute("D.GetStadiumTest(test={test}, name={name})")]
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [HttpGet]
- public IHttpActionResult GetStadiumTest([FromODataUri] string test, [FromODataUri] string name)
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = name, Name = test, Owner = "FC Zug" } });
- }
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("D.GetStadiumsWithFunction()")]
- [HttpGet]
- public IHttpActionResult GetStadiumsWithFunction()
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "FC Zug" } });
- }
- // http://localhost:60096/odata/Stadium(Name='Baz', Country='Germany')/D.GetCityFromStadiumWithFunction()
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("(Name={name},Country={country})/D.GetCityFromStadiumWithFunction()")]
- [HttpGet]
- public IHttpActionResult GetCityFromStadiumWithFunction([FromODataUri] string name, [FromODataUri] string country)
- {
- return Ok(new City { Population = 9000000, Country = "Berlin", Id = 8 });
- }
- }
- }
Complete OData CityController
- using System.Collections.Generic;
- using System.Web.Http;
- using System.Web.OData;
- using System.Web.OData.Query;
- using System.Web.OData.Routing;
- using WebAPIODataKeys.Models;
- namespace WebApiODataKeys.Controllers
- {
- public class CityController : ODataController
- {
- public IHttpActionResult Get()
- {
- return Ok(new List<City> { new City { Population = 2300000, Country = "Switzerland", Id=1} });
- }
- public IHttpActionResult Get(int key)
- {
- return Ok(new City { Population = 9000000, Country = "Berlin", Id = key });
- }
- [EnableQuery(PageSize = 20, AllowedQueryOptions = AllowedQueryOptions.All)]
- [ODataRoute("City({key})/D.GetStadiumsFromCityWithFunction()")]
- [HttpGet]
- public IHttpActionResult GetStadiumsFromCityWithFunction(int key)
- {
- return Ok(new List<Stadium> { new Stadium { Capacity = 2300, Country = "Switzerland", Name = "Times Stadium", Owner = "FC Zug" } });
- }
- }
- }
Links:
http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-routing-conventions
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/
http://blogs.msdn.com/b/odatateam/
[转]Web API OData V4 Keys, Composite Keys and Functions Part 11的更多相关文章
- ASP.NET 4.x Web Api Odata v4 backend modify query 修改查询
有时候我们会想给予权限添加 filter 到查询上. 比如 会员和管理员都使用了 /api/products 作为 product 查询 但是会员不应该可以看见还没有上架的货品 /api/produc ...
- [转]How to Use Web API OData to Build an OData V4 Service without Entity Framework
本文转自:http://www.odata.org/blog/how-to-use-web-api-odata-to-build-an-odata-v4-service-without-entity- ...
- node-odata: ASP.NET WEB API OData的替代品
什么是 OData 协议? OData, 相信身为 .NET 程序员应该不为陌生, 尤其是它的实现: ASP.NET WEB API OData. 对于 OData, 官网上对其的定义是 OData ...
- vs2012 + web api + OData + EF + MYsql
vs2012 + web api + OData + EF + MYsql 开发及部署 先说下我的情况,b/s开发这块已经很久没有搞了,什么web api .MVC.OData都只是听过,没有实际开发 ...
- 使用ASP.Net MVC5 Web API OData和Sencha Touch 开发WebAPP
使用ASP.Net MVC5 Web API OData和SenCha Touch 开发WebAPP Demo 效果 第一步 创建数据库 创建表 第二步 搭建MVC,并导入OData 第三步,写入We ...
- [转]Support Composite Key in ASP.NET Web API OData
本文转自:https://code.msdn.microsoft.com/Support-Composite-Key-in-d1d53161 he default EntitySetControlle ...
- 如何使用ASP.NET Web API OData在Oracle中使用Entity Framework 6.x Code-First方式开发 OData V4 Service
环境: Visual Studio 2013 + .Net Framework 4.5.2 1.新建项目 2.安装OData,ODP.NET 安装的包: 下面是部分代码: using System; ...
- vs2012 + web api + OData + EF + MYsql 开发及部署
先说下我的情况,b/s开发这块已经很久没有搞了,什么web api .MVC.OData都只是听过,没有实际开发过,因为最近要开发一个手机app的服务端,所以准备用这套框架来开发. 下面开始进入正题( ...
- [转]vs2012 + web api + OData + EF + MYsql 开发及部署
本文转自:http://www.cnblogs.com/liumang/p/4403436.html 先说下我的情况,b/s开发这块已经很久没有搞了,什么web api .MVC.OData都只是听过 ...
随机推荐
- Js异常捕获
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 基于ASP.NET的MVC框架下的MvcPaper分页控件的使用技术
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Webdiyer. ...
- IIS服务器添加网站
1.添加IIS服务:对“我的电脑”右键,管理,点击服务和应用程序,如果下面没有”Internet Information Services(IIS)管理器“,打开控制面板,点击程序,启用或者关闭Win ...
- Android intent 传值不更新的原因和解决办法
当 Activity 的启动模式是 singleTask 或者 singleInstance 的时候.如果使用了 intent 传值,则可能出现 intent 的值无法更新的问题.也就是说每次 int ...
- c++ 多态总结
C++的多态性用一句话概括就是: 在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数. 如果对象类型是派生类,就调用派生类的函数:如果对象类型是 ...
- VMware Workstation 14 pro License Keys
AC5XK-0ZD4H-088HP-9NQZV-ZG2R4 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 ZC3WK-AFXEK-488JP-A7MQX-XL8YF ZC5XK-A6E0 ...
- Ubuntu下实现socks代理转http代理
代理(英语:Proxy),也称网络代理,是一种特殊的网络服务,允许一个网络终端(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接.一些网关.路由器等网络设备具备网络代理功能. ...
- 关于Mysql数据库查询数据大小写的问题汇总
前天在问答区看到一个童鞋对于mysql中大小写问题不熟悉,在回复他后再次汇总梳理如下: mysql中大小写问题主要有以下两种: A.表名区分大小写 ower_case_table_names 是表名区 ...
- HDU-6125-Friend-Graph-2017CCPC网络赛(图论,拉姆齐定理-组合数学)
Friend-Graph Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...
- 有向图的拓扑排序的理解和简单实现(Java)
如果图中存在环(回路),那么该图不存在拓扑排序,在这里我们讨论的都是无环的有向图. 什么是拓扑排序 一个例子 对于一部电影的制作过程,我们可以看成是一个项目工程.所有的工程都可以分为若干个" ...