OData(Open Data Protocol)是web的数据访问协议,提供统一的查询和操作数据集(CRUD: create, read, update和delete)。ASP.NET Web API 支持OData v3和v4,甚至v3的endpoint和v4的endpoint可以并行运行。本文所讲内容是在Web API轻量级应用中,使用Entity Framework来实现后端数据库,并实现支持CRUD操作的OData v4 endpoint。
solution全览
创建solution
http://blog.csdn.net/daimeisi123/article/details/46776725#t1 (与《OData v4 - Web API 轻量级应用(无Entity Framwork)》相同)
安装NuGet包
http://blog.csdn.net/daimeisi123/article/details/46776725#t2(与《OData v4 - Web API 轻量级应用(无Entity Framwork)》相同)
创建Models
在Models文件夹下创建一个model (Product.cs)
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
其中Id是entity key,Client能够通过Id查询到product entities,如Id=5,查询语句为“http://localhost:40596/Products(5)”
使用Entity Framework(EF)
在本文中将使用EF来创建后端数据库,当然这不是唯一的方法,我们也可以创建data-acces 层来将数据实体转换位Models。
-
安装EF NuGet 包
Tools->NuGet Package Manager->Package Manager Console
PM>Install-Package EntityFramework
-
配置Web.config
配置在本地运行时将调用的数据库,一个LocalDB database。
<configuration>
<configSections>
<!-- ... -->
</configSections>
<!-- Add this:connection string for a LocalDB database -->
<connectionStrings>
<add name="DemoDbContext" connectionString="Data Source=(localdb)\v11.0;
Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True;
AttachDbFilename=|DataDirectory|ProductsContext.mdf"
providerName="System.Data.SqlClient" />
</connectionStrings>
其中“name="ProductsContext"是connection的名字。
-
添加DbContext
在Models下添加ProductsContext
public class DemoDbContext: DbContext
{
public DemoDbContext()
: base("name=DemoDbContext") // Give the name of the connection string in Web.config
{
}
public DbSet<Product> Products { get; set; }
}
配置OData EndPoint
在App_Start/WebApiConfig.cs中配置OData。如果需要多个OData endpoints,需要分别创建路径和prefix
- 创建Entity Data Model(EDM)
- 添加路径(route)
//Creates an Entity Data Model (EDM).
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
//Adds a route (Tells Web API how to route HTTP requests to the endpoint. )
config.MapODataServiceRoute(routeName: "ODataRoute", routePrefix: null, model: builder.GetEdmModel());
添加OData Controller
controller是用来处理HTTP请求的,每一个entity都有对应的controller。
public class ProductsController : ODataController
{
//Uses the DemoDbContext class to access the database using EF
DemoDbContext db = new DemoDbContext();
//Judge if the product with this key is exist.
private bool ProductExists(int key)
{
return db.Products.Any(p => p.Id == key);
}
//Dispose of the DemoDbContext
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
/** CRUD(Create, read, update, delete)**/
[EnableQuery] //--Enables clients to modify the query(such as $filter, $sort, $page)
public IQueryable<Product> Get() // The entire Products collection
{
return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key) //Query a product by its key
{
IQueryable<Product> result = db.Products.Where(p => p.Id == key);
return SingleResult.Create(result);
}
// Add a new product to the database
public async Task<IHttpActionResult> Post(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
await db.SaveChangesAsync();
return Created(product);
}
//Updating an entity -- PATCH(A partial update)
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product)// Delta<T> type to track the changes
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var entity = await db.Products.FindAsync(key);
if (entity == null)
{
return NotFound();
}
product.Patch(entity);
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(entity);
}
//Updating an entity -- PUT(Replaces the entire entity)
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
db.Entry(update).State=EntityState.Modified;
try
{
await db.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(key))
{
return NotFound();
}
else
{
throw;
}
}
return Updated(update);
}
//Delete an entity
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
var product = await db.Products.FindAsync(key);
if (product == null)
{
return NotFound();
}
db.Products.Remove(product);
await db.SaveChangesAsync();
return StatusCode(HttpStatusCode.NoContent);
}
}