標籤:
前言
閱讀本文之前,您也可以到Asp.Net Web API 2 系列導航進行查看 http://www.cnblogs.com/aehyok/p/3446289.html。
本文的範例程式碼的為http://pan.baidu.com/s/1o6lqXN8
大多數的資料集定義實體間的關係:客戶有訂單、書籍有作者、產品有供應商。用戶端可以使用OData操作實體間的關係。給定一個產品,你可以找到該產品的供應商。您也可以建立或者刪除關係。例如,您也可以為一個產品設定一個供應商。
本教程將會展示在Asp.Net Web API中支援這些操作。本文的教程是建立在上一節的教程之上http://www.cnblogs.com/aehyok/p/3545824.html。
Add a Supplier Entity添加一個供應商實體類
首先我們需要來添加一個Supplier的實體類
namespace OData.Models{ public class Supplier { [Key] public string Key { get; set; } public string Name { get; set; } }}
這個類使用了一個字串類型的實體鍵。在實踐中,這可能比使用整形鍵不太常見的。但它是值得的看到OData如何處理除了整數以外的其他鍵類型。
接下來,我們將通過在Product類上添加一個Supplier的屬性來建立一個關係。
public class Product { public int ID { get; set; } public string Name { get; set; } public decimal Price { get; set; } public string Category { get; set; } // New code [ForeignKey("Supplier")] public string SupplierId { get; set; } public virtual Supplier Supplier { get; set; } }
添加一個新的DbSet到ProductServiceContext類,從而使Entity Framework將包括Supplier在資料庫表中。
public class ProductServiceContext : DbContext { public ProductServiceContext() : base("name=ProductServiceContext") { } public DbSet<Product> Products { get; set; } ///New Code public DbSet<Supplier> Suppliers { get; set; } }
在WebApiConfig.cs,添加一個“Suppliers”實體的EDM模型:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Product>("Products"); // New code: builder.EntitySet<Supplier>("Suppliers");
Navigation Properties導覽屬性
為了得到一個產品的供應商,用戶端發送了一個Get請求:
GET /Products(1)/Supplier
在Product類型上有一個Supplier的導覽屬性。在這個執行個體中,Supplier是一個單一的項。但是一個導覽屬性也能返回一個集合(一對多或者多對多的 關係)。
為了支援這個請求,在ProductsController上添加如下方法:
// GET /Products(1)/Supplier public Supplier GetSupplier([FromODataUri] int key) { Product product = db.Products.FirstOrDefault(p => p.ID == key); if (product == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } return product.Supplier; }
key這個參數就是這個Product的鍵。這個方法返回關聯的實體——在這個執行個體中,就是一個Supplier對象。方法的名稱和參數的名稱都是非常重要的。總之,如果導覽屬性被命名為一個“X”,你需要添加一個被命名為“GetX”的方法。這個方法必須採用一個命名為“key”的參數,用來匹配父類資料類型的key。
它也是很重要的在鍵參數上擁有【FromOdataUri】的屬性。當它從請求的URL中解析鍵時,這個屬性將會告訴Web API去使用Odata文法規則。
Creating and Deleting Links
OData支援建立和刪除兩個實體之間的關係。在OData術語中,這個關係就是一個“link”。每個link有一個攜帶entity/$links/entity的Url。例如,由產品到供應商的連結看起來像這樣:
/Products(1)/$links/Supplier
為了建立一個新的連結,這個用戶端發送了一個post請求到這個連結URI。請求的訊息體就是目標實體的URI。例如,假設有一個供應商的鍵為“CTSO”。為了建立一個連結由“Product(1)”到”Supplier(‘CTSO‘)“,用戶端發送一個請求如下:
POST http://localhost/odata/Products(1)/$links/SupplierContent-Type: application/jsonContent-Length: 50
{"url":"http://localhost/odata/Suppliers(‘CTSO‘)"}
對於刪除一個連結,用戶端發送了一個DELETE 請求到連結URI。
Creating Links
為啟用一個用戶端去建立產品-供應商的連結,需要在ProductsController類中添加如下的代碼:
[AcceptVerbs("POST", "PUT")]public async Task<IHttpActionResult> CreateLink([FromODataUri] int key, string navigationProperty, [FromBody] Uri link){ if (!ModelState.IsValid) { return BadRequest(ModelState); } Product product = await db.Products.FindAsync(key); if (product == null) { return NotFound(); } switch (navigationProperty) { case "Supplier": string supplierKey = GetKeyFromLinkUri<string>(link); Supplier supplier = await db.Suppliers.FindAsync(supplierKey); if (supplier == null) { return NotFound(); } product.Supplier = supplier; await db.SaveChangesAsync(); return StatusCode(HttpStatusCode.NoContent); default: return NotFound(); }}
這個方法有三個參數:
第一個key:就是引導到父類實體的鍵
第二個navigationProperty: 導覽屬性的名稱。例如,最合適的導覽屬性Supplier。
第三個link:被連結實體的OData的URI。這個值是從訊息體中獲得。例如,這個連結URI可能是”http://localhost/odata/Suppliers(‘CTSO‘)“,也就是供應商中有ID="CTSO"。
這個方法用這個連結去尋找Supplier。如果匹配的供應商被發現,這個方法將會設定Product實體類的Supplier的屬性,並且儲存結果到資料庫。
其中最難的部分是解析連結URI。從根本上來說,你需要類比發送一個get請求到那個URI。接下來的輔助方法將會展示如何處理它。這個方法調用Web API路由過程,返回一個OData實體,展現被轉換的OData路徑。對於一個連結URI,這個片段數中應該有一個實體鍵。
// Helper method to extract the key from an OData link URI.private TKey GetKeyFromLinkUri<TKey>(Uri link){ TKey key = default(TKey); // Get the route that was used for this request. IHttpRoute route = Request.GetRouteData().Route; // Create an equivalent self-hosted route. IHttpRoute newRoute = new HttpRoute(route.RouteTemplate, new HttpRouteValueDictionary(route.Defaults), new HttpRouteValueDictionary(route.Constraints), new HttpRouteValueDictionary(route.DataTokens), route.Handler); // Create a fake GET request for the link URI. var tmpRequest = new HttpRequestMessage(HttpMethod.Get, link); // Send this request through the routing process. var routeData = newRoute.GetRouteData( Request.GetConfiguration().VirtualPathRoot, tmpRequest); // If the GET request matches the route, use the path segments to find the key. if (routeData != null) { ODataPath path = tmpRequest.GetODataPath(); var segment = path.Segments.OfType<KeyValuePathSegment>().FirstOrDefault(); if (segment != null) { // Convert the segment into the key type. key = (TKey)ODataUriUtils.ConvertFromUriLiteral( segment.Value, ODataVersion.V3); } } return key;}
Deleting Links
對於刪除一個連結,在ProductsController類中添加如下代碼:
public async Task<IHttpActionResult> DeleteLink([FromODataUri] int key, string navigationProperty){ Product product = await db.Products.FindAsync(key); if (product == null) { return NotFound(); } switch (navigationProperty) { case "Supplier": product.Supplier = null; await db.SaveChangesAsync(); return StatusCode(HttpStatusCode.NoContent); default: return NotFound(); }}
在這個例子中,這個導覽屬性是一個簡單的Supplier實體。如果導覽屬性是一個集合,對於刪除一個連結的URI必須在被關聯的實體中有一個鍵。例如:
DELETE /odata/Customers(1)/$links/Orders(1)
這裡展示的則是1對多的關係中,刪除其中的一個的例子。
這個請求就是從客戶1中移除訂單為1的。這個DeleteLink方法將會有如下籤名:
void DeleteLink([FromODataUri] int key, string relatedKey, string navigationProperty);
簡單測試結果
1、http://localhost:3629/Odata/Products(1)/Supplier
2、
將ID=2的Supplier修改為WING
請求Header
POST http://localhost/odata/Products(2)/$links/SupplierContent-Type: application/jsonContent-Length: 50
請求Body
{"url":"http://localhost/odata/Suppliers(‘WING‘)"}
現在再次查看http://localhost/Odata/Products
3、DELETE http://localhost/odata/Products(2)/$links/Supplier那麼這樣就可以將上面的SupplierId=WING修改為null
然後再次執行http://localhost/Odata/Products查看
總結
本文所參考連結為http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations
本文範例程式碼為http://pan.baidu.com/s/1o6lqXN8
Asp.Net Web API 2第十八課——Working with Entity Relations in OData