Asp.Net Web API 2第十八课——Working with Entity Relations in OData
前言
阅读本文之前,您也可以到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
类,从而使实体框架将包括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()/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()/$links/Supplier
为了创建一个新的链接,这个客户端发送了一个post请求到这个链接URI。请求的消息体就是目标实体的URI。例如,假设有一个供应商的键为“CTSO”。为了创建一个链接由“Product(1)”到”Supplier('CTSO')“,客户端发送一个请求如下:
POST http://localhost/odata/Products(1)/$links/Supplier
Content-Type: application/json
Content-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()/$links/Orders()
这里展示的则是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/Supplier
Content-Type: application/json
Content-Length:
请求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的更多相关文章
- Asp.Net Web API 2第十六课——Parameter Binding in ASP.NET Web API(参数绑定)
导航 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html. 本文主要来讲解以下内容: ...
- Asp.Net Web API 2第十五课——Model Validation(模型验证)
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文参考链接文章地址htt ...
- Asp.Net Web API 2第十四课——Content Negotiation(内容协商)
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文描述ASP.NET W ...
- Asp.Net Web API 2第十二课——Media Formatters媒体格式化器
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本教程演示如何在ASP.N ...
- Asp.Net Web API 2(CRUD操作)第二课
Asp.Net Web API 2(CRUD操作)第二课 Asp.Net Web API 导航 Asp.Net Web API第一课:入门http://www.cnblogs.com/aehyok ...
- Asp.Net Web API 2第十课——使用OWIN自承载Web API
详情请查看http://aehyok.com/Blog/Detail/71.html 个人网站地址:aehyok.com QQ 技术群号:206058845,验证码为:aehyok 本文文章链接:ht ...
- Asp.Net Web API 2
Asp.Net Web API 2第十八课——Working with Entity Relations in OData 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导 ...
- 使用 OWIN Self-Host ASP.NET Web API 2
Open Web Interface for .NET (OWIN)在Web服务器和Web应用程序之间建立一个抽象层.OWIN将网页应用程序从网页服务器分离出来,然后将应用程序托管于OWIN的程序而离 ...
- Asp.Net Web API 2第八课——Web API 2中的属性路由
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 路由就是Web API如何 ...
随机推荐
- mysql之预处理语句prepare、execute、deallocate
预制语句的SQL语法基于三个SQL语句: PREPARE stmt_name FROM preparable_stmt; EXECUTE stmt_name [USING @var_name [, @ ...
- sublime text3 输入中文的解决方法及注册
让它输入中文的原理就是给sublime text3给打上个补丁libsublime-imfix.so,这个补丁可以直接git回来,或者下载补丁的源码编译安装. Ubuntu可以直接按照下面的教程 su ...
- angularjs 延迟更新和angularjsUI
angularjsUI库https://material.angularjs.org/latest/ ng-model-options="{ updateOn: 'blur' }" ...
- CLR VIA C#事件
事件是类型的一个成员,用来在事情发生的时候通知注册了该事件的成员. 事件和观察者模式十分的相似,所以事件应该提供如下几种能力 1.能让对象的方法登记对他的关注 2.能让对象的方法取消对他的关注 3.能 ...
- 《C和指针(Pointer on c)》 学习笔记
转载:http://dsqiu.iteye.com/blog/1687944 首先本文是对参考中三个连接的博客进行的整理,非常感谢三位博主的努力,每次都感叹网友的力量实在太强大了…… 第一章 快速上手 ...
- 深入理解js——函数和对象的关系
函数也是对象,但是函数却不像数组--数组是对象的一种,它是对象的一个子集.函数和数组之间不是单纯的包含与被包含的关系,它们之间有点像鸡生蛋蛋生鸡的逻辑. 来例子:function Fn(){ this ...
- arm64 boot
http://www.wowotech.net/linux_kenrel/arm64_initialize_1.html
- 灭顶之灾之网络电视精灵——S2 2.8
从前,有一个神奇的东西叫做搞搞精灵 关于他,有一段历史. 哎呀!我去!写不下去了. -.-以上玩笑 首先需求分析 TreeView显示两种频道 TypeA和TypeB 所以创建三个类 ChannelB ...
- java去中文
java 去中文 package a.b; public class TrimCNTool { public static boolean checkCNChar(char oneChar) { if ...
- eclipse构建及运行maven web项目
1:环境 eclipse indigo, JDK1.6, maven 3.2.1, tomcat7.0.42 2:安装eclipse maven插件 m2eclipse 第一种方法:从网上下载m2ec ...