C# OData Create (POST) Request with nested items

孤人 提交于 2021-02-05 07:39:56

问题


hoping I can have someone help me out with a problem I'm having. We're using a new product which interacts with our ERP system and exposes business objects through REST services using OData. They have some samples and everything which I've gone through but I'm stuck on a key process we're trying to use the product for, which is the creation of a sales document with many items in one request.

I've got the backend working on the server side accepting the request as I can create a POST request manually with a REST client in Firefox and the ERP system accepts the request and creates the document no problem.

The problem is, I'm trying to programatically create the request with just a simple C# console application, but I can't get the request to be created correctly.

Here is what the $metadata of the OData service looks like:

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

Now, if I create a request manually (following the instructions from the vendor of the software), the server accepts the request and creates the document in the ERP system. This is what that request looks like:

<?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>

However, using the following code in C#, I cannot get the Items to become part of the request. They just don't show up. Here is the 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);
        }

But this is the request that is generated:

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

I hope this makes sense...any help is much appreciated.

Thanks


回答1:


You need to explicitly tell the data service context (ser) that there is a link between these objects. Take a look at the AddLink and SetLink methods. The examples on those pages are very close to what you trying to do.

Bottom line, I think you need to add:

ser.AddLink(soHeader, "SalesOrderItems", soItem);
ser.SetLink(soItem, "SalesOrderHeader", soHeader);

Hope this helps.




回答2:


Well, according to the guys over on the MS forum, this type of deep insert request isn't supported by the WCF DS client as of right now.

Mega bummer.



来源:https://stackoverflow.com/questions/7959360/c-sharp-odata-create-post-request-with-nested-items

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!