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 大多数的数据集定义实体间的关系:客户有订单、书籍有作者、产品有供应商。

前言

  阅读本文之前,您也可以到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; }
    }

添加一个新DbSetProductServiceContext类,从而使实体框架将包括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/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(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/Supplier
Content-Type: application/json
Content-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

目录
相关文章
|
2月前
|
编解码 前端开发 JavaScript
.NET_web前端框架_layui_栅格布局
【8月更文挑战第27天】
38 4
|
12天前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
12天前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
33 3
|
16天前
|
开发框架 前端开发 .NET
VB.NET中如何利用ASP.NET进行Web开发
在VB.NET中利用ASP.NET进行Web开发是一个常见的做法,特别是在需要构建动态、交互式Web应用程序时。ASP.NET是一个由微软开发的开源Web应用程序框架,它允许开发者使用多种编程语言(包括VB.NET)来创建Web应用程序。
43 5
|
1天前
|
监控 安全 API
最完美的扩展Docker + .NET API:简化部署和扩展
最完美的扩展Docker + .NET API:简化部署和扩展
6 0
|
1天前
|
API
使用`System.Net.WebClient`类发送HTTP请求来调用阿里云短信API
使用`System.Net.WebClient`类发送HTTP请求来调用阿里云短信API
7 0
|
1天前
|
存储 开发框架 JSON
ASP.NET Core OData 9 正式发布
【10月更文挑战第8天】Microsoft 在 2024 年 8 月 30 日宣布推出 ASP.NET Core OData 9,此版本与 .NET 8 的 OData 库保持一致,改进了数据编码以符合 OData 规范,并放弃了对旧版 .NET Framework 的支持,仅支持 .NET 8 及更高版本。新版本引入了更快的 JSON 编写器 `System.Text.UTF8JsonWriter`,优化了内存使用和序列化速度。
|
2月前
|
存储 JSON API
【Azure 存储服务】使用REST API操作Azure Storage Table,删除数据(Delete Entity)
【Azure 存储服务】使用REST API操作Azure Storage Table,删除数据(Delete Entity)
【Azure 存储服务】使用REST API操作Azure Storage Table,删除数据(Delete Entity)
|
2月前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
36 0
|
1月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
29 7