【问题标题】:OData V4 client adding child entityOData V4 客户端添加子实体
【发布时间】:2017-03-06 22:39:08
【问题描述】:

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

我已经走了好几条路,但我什至不确定哪条路是正确的。
让我们假设它们之间的导航已经正常工作。
我可以 $expand=OrderDetails 很好,我也可以 Orders(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) 它会抛出一个错误。

{"error":{"code":"","message":"没有找到与请求 URI 'http://localhost/Test/odata/Orders(1)/OrderDetails'匹配的 HTTP 资源。","innererror":{"message":"No发现路由约定使用模板'~/entityset/key/navigation'为 OData 路径选择一个操作。","type":"","stacktrace":""}}}

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

第二轮

// 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”。

{"error":{"code":"","message":"没有找到与请求 URI 'http://localhost/Test/odata/Orders(1)/OrderDetails/$ref'匹配的 HTTP 资源。","innererror":{"message": “没有找到路由约定来为模板 '~/entityset/key/navigation/$ref' 的 OData 路径选择操作。”,"type":"","stacktrace":""}}}

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

第三轮

// 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;

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

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

有什么想法吗?

【问题讨论】:

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


    【解决方案1】:

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

    看看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);
        }
    

    【讨论】:

    • 感谢您提供的信息,但经过反复试验,我找到了答案。在我尝试将孩子添加到父母的方式中,这是客户端的一个问题。
    【解决方案2】:

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

    // 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();
    

    【讨论】:

      猜你喜欢
      • 2016-11-22
      • 2014-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多