#c# #post #odata
#c# #Публикация #odata
Вопрос:
надеюсь, что кто-нибудь поможет мне решить проблему, с которой я столкнулся. Мы используем новый продукт, который взаимодействует с нашей ERP-системой и предоставляет доступ к бизнес-объектам через службы REST с использованием OData. У них есть несколько примеров и все, через что я прошел, но я застрял на ключевом процессе, для которого мы пытаемся использовать продукт, а именно на создании документа продажи со многими элементами в одном запросе.
У меня есть серверная часть, работающая на стороне сервера, принимающая запрос, поскольку я могу создать POST-запрос вручную с помощью REST-клиента в Firefox, и ERP-система принимает запрос и создает документ без проблем.
Проблема в том, что я пытаюсь программно создать запрос с помощью простого консольного приложения C #, но я не могу заставить запрос быть созданным правильно.
Вот как выглядит $metadata службы OData:
<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:gp="http://www.sap.com/Protocols/SAPData/GenericPlayer" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:sap="http://www.sap.com/Protocols/SAPData" Version="1.0">
<edmx:DataServices m:DataServiceVersion="2.0">
<Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm" Namespace="SALES_ORDER">
<EntityType Name="SalesOrderHeader" sap:content-version="1">
<Key>
<PropertyRef Name="OrderId"/>
</Key>
<Property Name="OrderId" Type="Edm.String" Nullable="false" MaxLength="10" sap:label="Sales Document" sap:filterable="false"/>
<Property Name="DocumentType" Type="Edm.String" MaxLength="4" sap:label="Sales Doc. Type" sap:filterable="false"/>
<Property Name="DocumentDate" Type="Edm.DateTime" Precision="10" sap:label="Document Date" sap:filterable="false"/>
<Property Name="CustomerId" Type="Edm.String" MaxLength="10" sap:label="Sold-to party" sap:filterable="true"/>
<Property Name="SalesOrg" Type="Edm.String" MaxLength="4" sap:label="Sales Org." sap:filterable="false"/>
<Property Name="DistChannel" Type="Edm.String" MaxLength="2" sap:label="Distr. Channel" sap:filterable="false"/>
<Property Name="Division" Type="Edm.String" MaxLength="2" sap:label="Division" sap:filterable="false"/>
<Property Name="OrderValue" Type="Edm.Decimal" Precision="21" Scale="2" sap:label="Net value" sap:filterable="false"/>
<Property Name="Currency" Type="Edm.String" MaxLength="5" sap:label="Doc. Currency" sap:filterable="false" sap:semantics="currency-code"/>
<NavigationProperty Name="SalesOrderItems" Relationship="SALES_ORDER.SalesOrderHeader_SalesOrderItems" FromRole="FromRole_SalesOrderHeader_SalesOrderItem" ToRole="ToRole_SalesOrderItem_SalesOrderHeader"/>
</EntityType>
<EntityType Name="SalesOrderItem" sap:content-version="1">
<Key>
<PropertyRef Name="OrderId"/>
<PropertyRef Name="Item"/>
</Key>
<Property Name="OrderId" Type="Edm.String" Nullable="false" MaxLength="10" sap:label="Sales Document" sap:filterable="false"/>
<Property Name="Item" Type="Edm.String" Nullable="false" MaxLength="6" sap:label="Item" sap:filterable="false"/>
<Property Name="Material" Type="Edm.String" MaxLength="18" sap:label="Material" sap:filterable="false"/>
<Property Name="Description" Type="Edm.String" MaxLength="40" sap:label="Description" sap:filterable="false"/>
<Property Name="Plant" Type="Edm.String" MaxLength="4" sap:label="Plant" sap:filterable="false"/>
<Property Name="Quantity" Type="Edm.Decimal" Precision="19" Scale="3" sap:label="Order quantity" sap:filterable="false"/>
<Property Name="UOM" Type="Edm.String" MaxLength="3" sap:label="Sales unit" sap:filterable="false" sap:semantics="unit-of-measure"/>
<Property Name="Value" Type="Edm.Decimal" Precision="21" Scale="2" sap:label="Net value" sap:filterable="false"/>
<NavigationProperty Name="SalesOrderHeader" Relationship="SALES_ORDER.SalesOrderItem_SalesOrderHeader" FromRole="FromRole_SalesOrderItem_SalesOrderHeader" ToRole="ToRole_SalesOrderHeader_SalesOrderItem"/>
</EntityType>
<Association Name="SalesOrderHeader_SalesOrderItems" sap:content-version="1">
<End Type="SALES_ORDER.SalesOrderHeader" Multiplicity="1" Role="FromRole_SalesOrderHeader_SalesOrderItem"/>
<End Type="SALES_ORDER.SalesOrderItem" Multiplicity="*" Role="ToRole_SalesOrderItem_SalesOrderHeader"/>
</Association>
<Association Name="SalesOrderItem_SalesOrderHeader" sap:content-version="1">
<End Type="SALES_ORDER.SalesOrderItem" Multiplicity="1" Role="FromRole_SalesOrderItem_SalesOrderHeader"/>
<End Type="SALES_ORDER.SalesOrderHeader" Multiplicity="1" Role="ToRole_SalesOrderHeader_SalesOrderItem"/>
</Association>
<EntityContainer Name="SALES_ORDER" m:IsDefaultEntityContainer="true">
<EntitySet Name="SalesOrderHeaders" EntityType="SALES_ORDER.SalesOrderHeader" sap:content-version="1"/>
<EntitySet Name="SalesOrderItems" EntityType="SALES_ORDER.SalesOrderItem" sap:content-version="1"/>
<AssociationSet Name="AssocSet_SalesOrderHeader_SalesOrderItems" Association="SALES_ORDER.SalesOrderHeader_SalesOrderItems" sap:content-version="1">
<End EntitySet="SalesOrderHeaders" Role="FromRole_SalesOrderHeader_SalesOrderItem"/>
<End EntitySet="SalesOrderItems" Role="ToRole_SalesOrderItem_SalesOrderHeader"/>
</AssociationSet>
<AssociationSet Name="AssocSet_SalesOrderItem_SalesOrderHeader" Association="SALES_ORDER.SalesOrderItem_SalesOrderHeader" sap:content-version="1">
<End EntitySet="SalesOrderItems" Role="FromRole_SalesOrderItem_SalesOrderHeader"/>
<End EntitySet="SalesOrderHeaders" Role="ToRole_SalesOrderHeader_SalesOrderItem"/>
</AssociationSet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Теперь, если я создаю запрос вручную (следуя инструкциям поставщика программного обеспечения), сервер принимает запрос и создает документ в ERP-системе. Вот как выглядит этот запрос:
<?xml version="1.0" encoding="UTF-8"?>
<atom:entry
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<atom:content type="application/xml">
<m:properties>
<d:DocumentType>ZCSH</d:DocumentType>
<d:CustomerId>0001008657</d:CustomerId>
<d:SalesOrg>1100</d:SalesOrg>
<d:DistChannel>10</d:DistChannel>
<d:Division>40</d:Division>
</m:properties>
</atom:content>
<atom:link
href="SalesOrderHeaders(0000004970)/SalesOrderItems"
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/SalesOrderItems"
type="application/atom xml;type=feed"
title="SALES_ORDER.SalesOrderHeader_SalesOrderItems">
<m:inline>
<atom:feed>
<atom:entry>
<atom:content type="application/xml">
<m:properties>
<d:Item>000010</d:Item>
<d:Material>70000559</d:Material>
<d:Plant>570B</d:Plant>
<d:Quantity m:Type="Edm.Decimal">1.000</d:Quantity>
</m:properties>
</atom:content>
</atom:entry>
<atom:entry>
<atom:content type="application/xml">
<m:properties>
<d:Item>000020</d:Item>
<d:Material>70000559</d:Material>
<d:Plant>570B</d:Plant>
<d:Quantity m:Type="Edm.Decimal">5</d:Quantity>
</m:properties>
</atom:content>
</atom:entry>
</atom:feed>
</m:inline>
</atom:link>
</atom:entry>
Однако, используя следующий код на C #, я не могу заставить элементы стать частью запроса. Они просто не отображаются. Вот C#:
ServiceReference4.SALES_ORDER ser = new ServiceReference4.SALES_ORDER(uri);
NetworkCredential c = nc;
ser.WritingEntity = new EventHandler<System.Data.Services.Client.ReadingWritingEntityEventArgs>(ser_WritingEntity);
ser.SendingRequest = new EventHandler<System.Data.Services.Client.SendingRequestEventArgs>(ser_SendingRequest);
ser.Credentials = c;
ServiceReference4.SalesOrderHeader soHeader = new ServiceReference4.SalesOrderHeader();
ServiceReference4.SalesOrderItem soItem = new ServiceReference4.SalesOrderItem();
soHeader = ServiceReference4.SalesOrderHeader.CreateSalesOrderHeader("");
soHeader.DocumentType = "ZCSH";
soHeader.DistChannel = "10";
soHeader.Division = "40";
soHeader.SalesOrg = "1100";
soItem = ServiceReference4.SalesOrderItem.CreateSalesOrderItem("", "10".PadLeft(6, '0'));
soItem.Material = "70000559".PadLeft(18, '0');
soItem.Plant = "570B";
soItem.Quantity = 1;
soItem.SalesOrderHeader = soHeader;
soHeader.SalesOrderItems.Add(soItem);
ser.AddToSalesOrderHeaders(soHeader);
try
{
System.Data.Services.Client.DataServiceResponse resp = ser.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message Environment.NewLine ex.InnerException);
}
Но это запрос, который генерируется:
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
<category scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" term="SALES_ORDER.SalesOrderHeader" />
<title />
<author>
<name />
</author>
<updated>2011-10-31T20:27:42.5387007Z</updated>
<id>http://.../sap/opu/sdata/sap/SALES_ORDER/SalesOrderHeaders('')</id>
<content type="application/xml">
<m:properties>
<d:Currency m:null="true" />
<d:CustomerId m:null="true" />
<d:DistChannel>10</d:DistChannel>
<d:Division>40</d:Division>
<d:DocumentDate m:type="Edm.DateTime" m:null="true" />
<d:DocumentType>ZCSH</d:DocumentType>
<d:OrderId m:null="false" />
<d:OrderValue m:type="Edm.Decimal" m:null="true" />
<d:SalesOrg>1100</d:SalesOrg>
</m:properties>
</content>
</entry>
Я надеюсь, что это имеет смысл … любая помощь очень ценится.
Спасибо
Комментарии:
1. Также я нашел на сайте odata это: odata.org/developers/protocols/operations#CreatingnewEntries если вы прокрутите вниз до абзаца, начинающегося словами «Когда клиенту необходимо создать несколько связанных записей, он может сделать это как независимые операции или — если связи между записями позволяют это структурно — они могут выполнить одну запись с деревом записей».Это именно то, что я хочу, и показанный POST-запрос — это именно то, что мне нужно выполнить, я просто не могу понять, как это сделать!
Ответ №1:
Вам необходимо явно указать контексту службы данных (ser), что между этими объектами существует связь. Взгляните на методы AddLink и SetLink . Примеры на этих страницах очень близки к тому, что вы пытаетесь сделать.
Итог, я думаю, вам нужно добавить:
ser.AddLink(soHeader, "SalesOrderItems", soItem);
ser.SetLink(soItem, "SalesOrderHeader", soHeader);
Надеюсь, это поможет.
Комментарии:
1. треугольник, спасибо за ответ. Я ударился головой об стену с этим. Я тоже попробовал то, что вы предложили, но результаты те же, запрос по-прежнему выглядит одинаково.
2. Я только что заметил, что вы не добавляете SalesOrderItem в контекст службы данных. Можете ли вы попробовать добавить ser. AddToSalesOrderItems(soItems); и посмотреть, поможет ли это?
3. Только что попробовал, тот же результат… вот что у меня есть сейчас:
ser.AddToSalesOrderHeaders(soHeader); ser.AddToSalesOrderItems(soItem); ser.AddLink(soHeader, "SalesOrderItems", soItem);
4. Вы также выполняете SetLink? Я только что снова просмотрел документы и увидел, что есть метод AddRelatedObject, который делает то, что AddObject , AddLink и SetLink должны делать за один вызов. Проверьте это: msdn.microsoft.com/en-us/library /…
5. lol я как раз собирался опубликовать, я просто попробовал AddRelatedObject, те же результаты… это сводит с ума!
Ответ №2:
Ну, по словам ребят на форуме MS, этот тип запроса на глубокую вставку на данный момент не поддерживается клиентом WCF DS.
Мега облом.