2016-10-25 7 views
0

У меня есть родительский (Заказ) и дочерний (OrderDetail), где Заказ уже существует в базе данных, а OrderDetail также существует в базе данных.
Все, что я действительно хочу сделать, это добавить еще одну запись OrderDetail, связанную с Орденом.Клиент OData V4, добавляющий дочерний объект

У меня было несколько путей, и я даже не уверен, что это правильный путь.
Давайте сделаем некоторые предположения, что навигационные операции между ними уже работают.
Я могу $ 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.": { "Сообщение":» не было найдено ни одной конвенции маршрутизации выбрать действие для пути OData с шаблоном '~/EntitySet/ключ/навигации "" тип. ":"», "StackTrace": ""}}}

Но если я перейду к указанному URL-адресу, он отобразит данные.
Время для Fiddler.
В Fiddler я вижу, что это POST для URL-адреса, а не 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/ $ реф'", "innererror": { "сообщение" : «Было найдено соглашение о маршрутизации для выбора действия для пути OData с шаблоном« ~/entityset/key/navigation/$ ref ».», «Type»: «", "stacktrace": ""}}}

Ну, быстрый поиск в Интернете привел меня к этой статье Entity Relations in OData v4 Using ASP.NET Web API 2.2
В этой статье говорится, что мне нужно добавить «CreateRef» в контроллере Orders.
Я создал «CreateRef» в контроллере Orders и, конечно же, получил его имя, но в статье предполагается, что OrderDetail существует в базе данных.
Это не сообщение json OrderDetail.

Round 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.

Я чувствую, что я так близко, но я не могу понять, как заставить его работать должным образом.

Любые идеи?

ответ

0

После проб и ошибок я нашел то, что работал.

0

У меня была такая же проблема и решение сегодня.

Взгляните на http://aspnetwebstack.codeplex.com/discussions/457028:

Там нет встроенных конвенций для обработки POST запросов к ~/EntitySet (ключ)/навигации. Вы должны построить его самостоятельно. Посмотрите на это 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); 
    } 
+0

Спасибо за информацию, но после проб и ошибок я смог найти ответ. Это была проблема на стороне клиента, так как я пытался добавить ребенка к родительскому. – goroth