C # OData Создать (ОПУБЛИКОВАТЬ) запрос с вложенными элементами

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

Мега облом.