0

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

我已经走了好几条路,我什至不确定什么是正确的路。
让我们假设它们之间的导航已经在工作。
我可以 $expand=OrderDetails 很好,我也可以 Orders(1)/OrderDetails 很好,并从 OrderDetails 执行相反的操作。

基于此更新数据服务,我需要做的就是调用 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":"没有找到路由约定来为带有模板 '~/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":"","堆栈跟踪”:””}}}

好吧,一个快速的网络搜索让我看到了这篇文章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

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

有任何想法吗?

4

2 回答 2

0

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

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

没有内置约定来处理对 ~/entityset(key)/navigation 的 POST 请求。你必须自己建造一个。查看此示例代码

您需要首先创建一个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);
    }
于 2016-10-27T16:12:11.293 回答
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();
于 2016-10-28T00:53:38.777 回答