OData V4客户端添加子实体

时间:2016-10-25 02:36:30

标签: c# asp.net asp.net-web-api2 odata odata-v4

我有一个父(Order)和子(OrderDetail),其中Order已存在于数据库中,OrderDetail也存在于数据库中。
我真正想做的就是添加绑定到Order的另一个OrderDetail记录。

我走了几条路,我甚至不确定路径是什么 让我们假设它们之间的导航已经起作用 我可以$ expand = OrderDetails很好,我也可以订单(1)/ OrderDetails罚款,并从OrderDetails反向。

基于此Updating the Data Service,我需要做的就是调用AddRelatedObject,然后将对象添加到OrderDetails集合中。

// Add the new item with a link to the related Order
context.AddRelatedObject(order, "OrderDetails", newOrderDetail);
// Add the new order detail to the collection
order.Order_Details.Add(newOrderDetail);
newOrderDetail.Order = order;

看起来很简单。
然而,当我执行context.SaveChanges(SaveChangesOptions.ReplaceOnUpdate)时,它将抛出一个错误。

  

{"错误":{"代码":"","消息":"未找到HTTP资源匹配请求URI' http://localhost/Test/odata/Orders(1)/OrderDetails'。"," innererror":{" message":"没有路由约定发现用模板'〜/ entityset / key / navigation'选择OData路径的动作。"," type":"", "堆栈跟踪":""}}}

但如果我导航到列出的网址,则会显示数据 提琴手的时间。
在Fiddler中,我可以看到这是对URL的POST而不是GET 它应该是POST而不是列出的URL POST应该是/ odata / OrderDetails

第2轮

// Add the new item with a link to the related Order
context.AttachTo("OrderDetails", newOrderDetail);
// Add a link between Order and the new OrderDetail
context.AddLink(order, "OrderDetails", newOrderDetail);
// Add the new order detail to the collection
order.Order_Details.Add(newOrderDetail);
newOrderDetail.Order = order;

仍然是一个错误的POST,但URL略有不同,json只发布了" / odata / OrderDetail(0)"它现在也有" $ ref"。

  

{"错误":{"代码":"","消息":"未找到HTTP资源匹配请求URI' http://localhost/Test/odata/Orders(1)/OrderDetails/ $ ref'。"," innererror":{" message":" No routing找到了约会,用模板'〜/ entityset / key / navigation / $ ref'选择一个OData路径的动作。"," type":"& #34;"堆栈跟踪":""}}}

快速的网络搜索让我看到了这篇文章Entity Relations in OData v4 Using ASP.NET Web API 2.2 这篇文章说我需要添加一个" CreateRef"在订单控制器中。
我确实创建了一个" CreateRef"在Orders控制器中,当然它被调用但是文章假设OrderDetail存在于数据库中 它没有发布json OrderDetail对象。

第3轮

// Add the new item with a link to the related Order
context.AttachTo("OrderDetails", newOrderDetail);
// Attach a link between Order and the new OrderDetail
context.AttachLink(order, "OrderDetails", newOrderDetail);
// Add the new order detail to the collection
order.Order_Details.Add(newOrderDetail);
newOrderDetail.Order = order;

这似乎好多了。
没有错误,但没有完全奏效 它发送了一个PUT到/ odata / OrderDetails(0)并且确实发送了json OrderDetail对象但是这应该是 POST而不是PUT

我觉得我如此接近但我似乎无法弄清楚如何让它正常工作。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我遇到了同样的问题,今天找到了解决方案。

看看http://aspnetwebstack.codeplex.com/discussions/457028

  

没有内置约定来处理对〜/ entityset(key)/ navigation的POST请求。你必须自己建一个。请查看此a sample code

首先需要创建EntitySetRoutingConvention

public class CreateNavigationPropertyRoutingConvention : EntitySetRoutingConvention
{
    public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
    {
        if (odataPath.PathTemplate == "~/entityset/key/navigation" && controllerContext.Request.Method == HttpMethod.Post)
        {
            IEdmNavigationProperty navigationProperty = (odataPath.Segments[2] as NavigationPathSegment).NavigationProperty;
            controllerContext.RouteData.Values["key"] = (odataPath.Segments[1] as KeyValuePathSegment).Value; // set the key for model binding.
            return "PostTo" + navigationProperty.Name;
        }

        return null;
    }
}

然后,您必须在WebApiConfig.Register

中注册
var routingConventions = ODataRoutingConventions.CreateDefault();
routingConventions.Insert(0, new CreateNavigationPropertyRoutingConvention());
server.Configuration.Routes.MapODataRoute("odata", "", GetEdmModel(), new DefaultODataPathHandler(), routingConventions);

请注意,此示例适用于oData v3,但可以轻松转换为v4。

然后,您只需将父对象添加到上下文中,并对所有子项使用AddRelatedObject。 您的请求将发送到ParentController

中的此空白处
public HttpResponseMessage PostToOrders([FromODataUri] int key, Order order)
    {
        // create order.
        return Request.CreateResponse(HttpStatusCode.Created, order);
    }

答案 1 :(得分:0)

经过反复试验,我发现了一些有效的方法。

// create a new order detail
OrderDetail newOrderDetail = new OrderDetail();
// set the orderID on the new order detail
newOrderDetail.OrderID = order.ID;
// add the order back as a link on the order detail
newOrderDetail.Order = order;
// add the order detail to the order detail collection on the order
order.OrderDetails.Add(newOrderDetail);
// add the order detail to the context
context.AddToOrderDetail(newOrderDetail);
// now update context for the order
context.UpdateObject(order);
// now save
context.SaveChanges();