快速搭建WebAPI(Odata+Code-First)附Odata条件查询表~
Odata是什么?
开放数据协议(Open Data Protocol,缩写OData)是一种描述如何创建和访问Restful服务的OASIS标准。该标准由微软发起,前三个版本1.0、2.0、3.0都是微软开放标准,遵循 [1] 。第四个版本4.0于2014年3月17日在OASIS投票通过成为开放工业标准 [2] 。
为什么需要OData?
OData是一个协议,一个标准。所以这个问题等同于为什么我们需要协议。类比TCP协议就可以理解一般。假设你开发的组件必须要和某个第三方组件通信,如果第三方组件不支持TCP而只支持其内部开发的一个私有协议,你就肯定头大了,你必须在你的组件里单独为其实现这个私有协议。如果大家都支持TCP协议,不就省事了么。这就是标准协议的作用:协议和标准用于制定一个统一通用的规则。 我们只需要按照这个协议或标准生产组件,那么这个组件就可以方便的和其他组件集成/协作。而无须根据其他组件的私有标准定制化组件。
如何使用OData?
Odata目前已经不怎么更新了,目前最高的5.7已经停留在2015年8月21 远古时代,然后我们还需要在WebApiConfig.cs中配置Odata
ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<TRoles>("TRoles"); builder.EntitySet<TUsers>("TUsers"); builder.EntitySet<TUsersRoles>("TUsersRoles"); config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
其中builder.EntitySet<TRoles>("TRoles"); 需要注意的是EntitySet这个方法是对你的实体类进行配置,其底层是要获取的类型放到它的配置项里。
Code-First 方式 create DataBase
Context.cs
public Model1() : base("name=CodeFirstDemo") { } public DbSet<TUsers> Users { get; set; } public DbSet<TRoles> Roles { get; set; } public DbSet<TUsersRoles> UsersRoles { get; set; }
其它的三个类就不写上来了,不想占用博客园的资源,也不想写没有意义的!
创建webAPIController
创建完的代码展示:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; using System.Web.Http.ModelBinding; using System.Web.Http.OData; using System.Web.Http.OData.Routing; using heheda.Models; namespace heheda.Controllers { /* The WebApiConfig class may require additional changes to add a route for this controller. Merge these statements into the Register method of the WebApiConfig class as applicable. Note that OData URLs are case sensitive. using System.Web.Http.OData.Builder; using System.Web.Http.OData.Extensions; using heheda.Models; ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<TRoles>("TRoles"); builder.EntitySet<TUsersRoles>("UsersRoles"); config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel()); */ public class TRolesController : ODataController { private Model1 db = new Model1(); // GET: odata/TRoles [EnableQuery] public IQueryable<TRoles> GetTRoles() { return db.Roles; } // GET: odata/TRoles(5) [EnableQuery] public SingleResult<TRoles> GetTRoles([FromODataUri] int key) { return SingleResult.Create(db.Roles.Where(tRoles => tRoles.Id == key)); } // PUT: odata/TRoles(5) public IHttpActionResult Put([FromODataUri] int key, Delta<TRoles> patch) { Validate(patch.GetEntity()); if (!ModelState.IsValid) { return BadRequest(ModelState); } TRoles tRoles = db.Roles.Find(key); if (tRoles == null) { return NotFound(); } patch.Put(tRoles); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { if (!TRolesExists(key)) { return NotFound(); } else { throw; } } return Updated(tRoles); } // POST: odata/TRoles public IHttpActionResult Post(TRoles tRoles) { if (!ModelState.IsValid) { return BadRequest(ModelState); } db.Roles.Add(tRoles); db.SaveChanges(); return Created(tRoles); } // PATCH: odata/TRoles(5) [AcceptVerbs("PATCH", "MERGE")] public IHttpActionResult Patch([FromODataUri] int key, Delta<TRoles> patch) { Validate(patch.GetEntity()); if (!ModelState.IsValid) { return BadRequest(ModelState); } TRoles tRoles = db.Roles.Find(key); if (tRoles == null) { return NotFound(); } patch.Patch(tRoles); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { if (!TRolesExists(key)) { return NotFound(); } else { throw; } } return Updated(tRoles); } // DELETE: odata/TRoles(5) public IHttpActionResult Delete([FromODataUri] int key) { TRoles tRoles = db.Roles.Find(key); if (tRoles == null) { return NotFound(); } db.Roles.Remove(tRoles); db.SaveChanges(); return StatusCode(HttpStatusCode.NoContent); } // GET: odata/TRoles(5)/TRolesUsersList [EnableQuery] public IQueryable<TUsersRoles> GetTRolesUsersList([FromODataUri] int key) { return db.Roles.Where(m => m.Id == key).SelectMany(m => m.TRolesUsersList); } protected override void Dispose(bool disposing) { if (disposing) { db.Dispose(); } base.Dispose(disposing); } private bool TRolesExists(int key) { return db.Roles.Count(e => e.Id == key) > 0; } } }
在之后我们就可以在前端中去通过这个协议规则去过滤我们的数据了!
Odata筛选数据规则表
操作 |
URL |
说明 |
$filter | http://localhost:8090/api/Meetings?$filter=ProductName eq 'Tofu' | 根据表达式的状态返回结果(返回ProductName 等于Tofu的Products) |
$orderby | http://localhost:8090/api/Meetings?$orderby=ProductName | 根据结果排序(根据ProductName列排序) |
$skip | http://localhost:8090/api/Meetings?$skip=10 | 越过结果中的n条数据,常用于分页 |
$top | http://localhost:8090/api/Meetings?$top=10 | 返回结果中的前n条记录,常用于分页 |
$select | http://localhost:8090/api/Meetings?$filter=ProductName eq 'Tofu'&$select=ProductName,UnitPrice | 选择需要返回的属性 |
$expand | http://localhost:8090/api/Meetings?$expand=Supplier | 返回Products中包含的导航属性(关联属性)Supplier |
$inlinecount | http://localhost:8090/api/Meetings?$inlinecount=allpages | 向服务器获取符合条件的资源总数(分页的total值) |