Skip to Content
Product Information
Author's profile photo Sana Faraz

Batch Operation in OData V2 Adapter in SAP Cloud Platform Integration

You can perform batch operations in the OData V2 Adapter for SAP Cloud Platform Integration. Batch, as its name suggests, implies that multiple requests are clubbed into one HTTP call. What this means is that if you are updating 100 records, instead of making 100 PUT or update request, the adapter would just make one call to the server with all the essential data. This would greatly improve time taken to achieve such requirements, also improving the performance.

The current OData V2 Adapter in SAP Cloud Platform Integration supports POST, PUT, MERGE,GET and DELETE HTTP operations in batch. Using the POST operation, you can insert ‘n’ number of new entities in your OData backend, using PUT/MERGE operation you can update entities and DELETE operation to delete entities. We will visit POST and PUT examples in the following sections.

To know more on how the OData Service supports batch you can go through OData documentation, http://www.odata.org/documentation/odata-version-2-0/batch-processing/ which will give you a brief overview on structure and format of a batch request.

 

Request Body for Batch Operation

The request body of batch contains an ordered sequence of operations to be performed. These modifying operations are called ‘ChangeSet’. ChangeSets are atomic units that contain the entity on which create, update or delete operations are to be performed. The ChangeSets can also contain an unordered sequence of operations. All changes in a ChangeSet must be all processed successfully or none of them. Implementation of ChangeSet varies with different services.

Here’s an example of the request body in SAP Cloud Platform Integration for ‘Batch Request’ which is denoted by a <batchParts> tag. This contains 2 ‘ChangeSets’ denoted by <batchChangeSet> tags. It is mandatory to have at least one ChangeSet in a batch request payload.

The <method> tag denotes which operation is to be performed. Iin this case, the operation is POST and the entity set is Categories. These tags are mandatory to be sent in all batch operations. There are a few optional tags like <headers> to send custom headers to ChangeSets. The <uri> tag is used to mention the exact entity on which you wish to perform the operation. It is mandatory in case of DELETE operation. Remember to add the key and its value when using <uri> tag for DELETE, MERGE or UPDATE operations.

Configuring Batch in the OData Adapter

We are using the OData Demo V2 service, http://services.odata.org/(S(btmy2xygehkm1gfrnpezr4xx))/V2/OData/OData.svc in this example.

  1. Select OData as the Receiver Adapter; screenshot of the adapter specific details is as seen below.
  2. Modelling Resource Path; connect to the service by adding a new system
  3. Enable ‘Batch Processing’ by switching to ON, after selecting the entity and operation of your choice. Here, entity is ‘Categories’ and Operation is ‘POST’.
  4. Click OK. Here’s a screenshot of how the adapter settings should look after modelling. Notice that the ‘Enable Batch Processing’ checkbox is enabled by default.

 

Note: Soon after modelling the operation, XSD file is generated and a message is displayed based on the fields selected by you in Step 3. This is to help you to map the request payload when using message mapping.

 

Understanding the Batch Response

Here’s an example of how the batch response looks like.

The first ChangeSet is the generic format and the second ChangeSet is an actual response received for the above request. Each individual ChangeSet response can be viewed under <batchChangeSetResponse> tag, which is followed by the <headers> tag. This <headers> tag denotes response headers from the OData Endpoint.

The <statusCode> and <statusInfo> gives us the HTTP status code and status line details respectively. <body> tag shows us the successfully inserted response in case of insert operations. It is empty for update operations. An error response is shown if either of the operations is unsuccessful. However, in the SAP Cloud Platform Integration’s message processing log (MPL), you will see that the status is COMPLETED. This is because, the batch requested has been accepted successfully by the OData server and it has provided a response.

 

Integration Flow with OData Batch

Scenario 1:With timer triggered event- Creating two new categories with body specified in the content modifier

The timer is configured to run once; the content modifier contains the request body. The response is captured in SFTP Server.

An example of batch request body is as seen below; we are inserting 2 new Categories with ID ‘25’ and ‘26’.

<batchParts>
	<batchChangeSet>
		<batchChangeSetPart>
			<method>POST</method>
			<Categories>
				<Category>
					<Name>Example1</Name>
					<ID>25</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
	</batchChangeSet>
	<batchChangeSet>
		<batchChangeSetPart>
			<method>POST</method>
			<Categories>
				<Category>
					<Name>Example2</Name>
					<ID>26</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
	</batchChangeSet>
</batchParts>

The output as observed in SFTP server is

<batchPartResponse>
    <batchChangeSetResponse>
      <batchChangeSetPartResponse>
        <headers>
          <Accept-Language></Accept-Language>
          <DataServiceVersion>1.0;</DataServiceVersion>
          <Location>http://services.odata.org/(S(btmy2xygehkm1gfrnpezr4xx))/V2/OData/OData.svc/Categories(25)</Location>
          <Accept></Accept>
          <Content-Type>application/atom+xml;charset=utf-8</Content-Type>
          <Cache-Control>no-cache</Cache-Control>
        </headers>
        <statusCode>201</statusCode>
        <body>
          <Name>Example1</Name>
          <ID>25</ID>
        </body>
        <contentId/>
        <statusInfo>Created</statusInfo>
      </batchChangeSetPartResponse>
    </batchChangeSetResponse>
    <batchChangeSetResponse>
      <batchChangeSetPartResponse>
        <headers>
          <Accept-Language></Accept-Language>
          <DataServiceVersion>1.0;</DataServiceVersion>
          <Location>http://services.odata.org/(S(btmy2xygehkm1gfrnpezr4xx))/V2/OData/OData.svc/Categories(26)</Location>
          <Accept></Accept>
          <Content-Type>application/atom+xml;charset=utf-8</Content-Type>
          <Cache-Control>no-cache</Cache-Control>
        </headers>
        <statusCode>201</statusCode>
        <body>
          <Name>Example2</Name>
          <ID>26</ID>
        </body>
        <contentId/>
        <statusInfo>Created</statusInfo>
      </batchChangeSetPartResponse>
    </batchChangeSetResponse>
  </batchPartResponse>

 

Scenario 2: Using XSD generated to form the batch request payload

SOAP adapter triggers the call to the OData Endpoint. The response is sent to SFTP server via SFTP adapter. The target mapping used is the XSD generated from the OData Receiver.

Batch request body is shown below. The first entity should be successfully updated and the second one should fail because there is no Category(123) currently in the OData server.

<batchParts>
	<batchChangeSet>
		<batchChangeSetPart>
			<method>PUT</method>
			<Categories>
				<Category>
					<Name>NewExample1</Name>
					<ID>25</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
	</batchChangeSet>
	<batchChangeSet>
		<batchChangeSetPart>
			<method>PUT</method>
			<Categories>
				<Category>
					<Name> NewExample2</Name>
					<ID>123</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
	</batchChangeSet>
</batchParts>

The output as observed in SFTP server is

<batchPartResponse>
	<batchChangeSetResponse>
		<batchChangeSetPartResponse>
			<headers>
				<Accept-Language/>
				<DataServiceVersion>1.0;</DataServiceVersion>
				<Accept/>
				<Cache-Control>no-cache</Cache-Control>
			</headers>
			<statusCode>204</statusCode>
			<body/>
			<contentId/>
			<statusInfo>No Content</statusInfo>
		</batchChangeSetPartResponse>
	</batchChangeSetResponse>
	<batchChangeSetResponse>
		<batchChangeSetPartResponse>
			<headers>
				<Accept-Language/>
				<DataServiceVersion>1.0;</DataServiceVersion>
				<Accept/>
				<Content-Type>application/xml</Content-Type>
			</headers>
			<statusCode>400</statusCode>
			<body>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;error xmlns=&quot;http://schemas.microsoft.com/ado/2007/08/dataservices/metadata&quot;&gt;
  &lt;code&gt;&lt;/code&gt;
  &lt;message xml:lang=&quot;en-US&quot;&gt;Error processing request stream. The URI specified is not valid.&lt;/message&gt;
  &lt;innererror&gt;
    &lt;message&gt;Invalid Uri specified. The query &apos;DataServiceProvider.DSPLinqQuery`1[DataServiceProvider.DSPResource]&apos; must refer to a single resource&lt;/message&gt;
    &lt;type&gt;System.ArgumentException&lt;/type&gt;
    &lt;stacktrace&gt;   at DataServiceProvider.DSPUpdateProvider.GetResource(IQueryable query, String fullTypeName) in c:\TFS\OData\Main\ndp\fx\src\DataWeb\ODataSDK\services.odata.org\DataServiceProvider\DSPUpdateProvider.cs:line 276&amp;#xD;
   at System.Data.Services.UpdatableWrapper.GetResource(IQueryable query, String fullTypeName)&lt;/stacktrace&gt;
  &lt;/innererror&gt;
&lt;/error&gt;</body>
			<contentId/>
			<statusInfo>Bad Request</statusInfo>
		</batchChangeSetPartResponse>
	</batchChangeSetResponse>
</batchPartResponse>

 

Scenario 3: Batch Request with multiple entries in one ChangeSet

The request payload that we will be using for this scenario is as seen below.

<batchParts>
	<batchChangeSet>
		<batchChangeSetPart>
			<method>POST</method>
			<Categories>
				<Category>
					<Name>Create Example 1</Name>
					<ID>16</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
		<batchChangeSetPart>
			<method>POST</method>
			<Categories>
				<Category>
					<Name>Create Example 2</Name>
					<ID>17</ID>
				</Category>
			</Categories>
		</batchChangeSetPart>
	</batchChangeSet>
	<batchChangeSet>
		<batchChangeSetPart>
			<method>PUT</method>
			<Categories>
				<Category>
					<Name>Updated Example 1</Name>
					<ID>16</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
		<batchChangeSetPart>
			<method>PUT</method>
			<Categories>
				<Category>
					<Name>Updated Example 2</Name>
					<ID>17</ID>
				</Category>
			</Categories>
		</batchChangeSetPart> 
	</batchChangeSet>
</batchParts>

Notice that, the request payload contains two ordered ChangeSets(batchChangeSet).

The first ChangeSet consists of two request to be performed(batchChangeSetPart), i.e creation of ID 16 and 17. If either of the ‘batchChangeSetPart’ fails neither will be completed. The rollback is performed by the OData Server if failure occurs.

These ‘batchChangeSetPart’ are unordered, meaning that any batchChangeSetPart can be performed first irrespective of the sequence in the payload.

The second ChangeSet consists of two update request of ID 16 and 17.

Successful response for the above request payload can be seen below. As of 2.27.0 version of Cloud Platform Integration, we allow only one response to be listed in the payload for each ChangeSet.

<batchPartResponse>
	<batchChangeSetResponse>
		<batchChangeSetPartResponse>
			<headers>
				<Accept-Language/>
				<DataServiceVersion>1.0;</DataServiceVersion>
				<Location>http://services.odata.org/(S(btmy2xygehkm1gfrnpezr4xx))/V2/OData/OData.svc/Categories(17)</Location>
				<Accept/>
				<Content-Type>application/atom+xml;charset=utf-8</Content-Type>
				<Cache-Control>no-cache</Cache-Control>
			</headers>
			<statusCode>201</statusCode>
			<body>
				<Name>Create Example 2</Name>
				<ID>17</ID>
			</body>
			<contentId/>
			<statusInfo>Created</statusInfo>
		</batchChangeSetPartResponse>
	</batchChangeSetResponse>
	<batchChangeSetResponse>
		<batchChangeSetPartResponse>
			<headers>
				<Accept-Language/>
				<DataServiceVersion>1.0;</DataServiceVersion>
				<Accept/>
				<Cache-Control>no-cache</Cache-Control>
			</headers>
			<statusCode>204</statusCode>
			<body/>
			<contentId/>
			<statusInfo>No Content</statusInfo>
		</batchChangeSetPartResponse>
	</batchChangeSetResponse>
</batchPartResponse>

 

Scenario 4: Batch GET Request

Batch GET request requires a request payload like other Batch operations but the XML structure offers. Below is an example of a request.

 

<batchParts>
    <batchQueryPart>
        <method>GET</method>
        <headers>
            <header>
                <headerName>dummy</headerName>
                <headerValue>dummy</headerValue>
            </header>
        </headers>
        <uri>./Products?$top=1</uri>
    </batchQueryPart>
    <batchQueryPart>
        <method>GET</method>
        <uri>Suppliers</uri>
    </batchQueryPart>
    <batchQueryPart>
        <method>GET</method>
        <uri>Categories(0)</uri>
    </batchQueryPart>
    <batchQueryPart>
        <method>GET</method>
        <uri>GetProductsByRating?rating=4</uri>
    </batchQueryPart>
</batchParts>

In this example, we are performing 4 different GET operations, i.e. reading the first ‘Product’, getting all the ‘Suppliers’, reading ‘Categories’ with for ID 0 and performing function import ‘GetProductsByRating’ respectively. <uri> tag is necessary for Batch GET. You can also see the XML tag is <batchQueryPart> instead of <batchChangeSet>. The <method> tag is missing as the operation is always GET. you can also add headers as seen in case for Entity ‘Product’. The response to the above request is as seen below.

<batchPartResponse>
    <batchQueryPartResponse>
      <headers>
        <Cache-Control>no-cache</Cache-Control>
        <Accept></Accept>
        <Accept-Language></Accept-Language>
        <DataServiceVersion>2.0;</DataServiceVersion>
        <Content-Type>application/atom+xml;charset=utf-8</Content-Type>
      </headers>
      <statusInfo>OK</statusInfo>
      <contentId/>
      <body>
        <Products>
          <Product>
            <Price>2.5</Price>
            <Rating>4</Rating>
            <DiscontinuedDate/>
            <ID>0</ID>
            <ReleaseDate>1992-01-01T00:00:00.000</ReleaseDate>
          </Product>
        </Products>
      </body>
      <statusCode>200</statusCode>
    </batchQueryPartResponse>
    <batchQueryPartResponse>
      <headers>
        <Cache-Control>no-cache</Cache-Control>
        <Accept></Accept>
        <Accept-Language></Accept-Language>
        <DataServiceVersion>1.0;</DataServiceVersion>
        <Content-Type>application/atom+xml;charset=utf-8</Content-Type>
      </headers>
      <statusInfo>OK</statusInfo>
      <contentId/>
      <body>
        <Suppliers>
          <Supplier>
            <Address>
              <State>WA</State>
              <ZipCode>98074</ZipCode>
              <Street>NE 228th</Street>
              <Country>USA</Country>
              <City>Sammamish</City>
            </Address>
            <Concurrency>0</Concurrency>
            <ID>0</ID>
            <Name>Exotic Liquids</Name>
          </Supplier>
          <Supplier>
            <Address>
              <State>WA</State>
              <ZipCode>98052</ZipCode>
              <Street>NE 40th</Street>
              <Country>USA</Country>
              <City>Redmond</City>
            </Address>
            <Concurrency>0</Concurrency>
            <ID>1</ID>
            <Name>Tokyo Traders</Name>
          </Supplier>
        </Suppliers>
      </body>
      <statusCode>200</statusCode>
    </batchQueryPartResponse>
    <batchQueryPartResponse>
      <headers>
        <Cache-Control>no-cache</Cache-Control>
        <Accept></Accept>
        <Accept-Language></Accept-Language>
        <DataServiceVersion>1.0;</DataServiceVersion>
        <Content-Type>application/atom+xml;charset=utf-8</Content-Type>
      </headers>
      <statusInfo>OK</statusInfo>
      <contentId/>
      <body>
        <Categories>
          <Category>
            <ID>0</ID>
            <Name>Food</Name>
          </Category>
        </Categories>
      </body>
      <statusCode>200</statusCode>
    </batchQueryPartResponse>
    <batchQueryPartResponse>
      <headers>
        <Cache-Control>no-cache</Cache-Control>
        <Accept></Accept>
        <Accept-Language></Accept-Language>
        <DataServiceVersion>2.0;</DataServiceVersion>
        <Content-Type>application/atom+xml;charset=utf-8</Content-Type>
      </headers>
      <statusInfo>OK</statusInfo>
      <contentId/>
      <body>
        <Products>
          <Product>
            <Price>2.5</Price>
            <Rating>4</Rating>
            <DiscontinuedDate/>
            <ID>0</ID>
            <ReleaseDate>1992-01-01T00:00:00.000</ReleaseDate>
          </Product>
        </Products>
      </body>
      <statusCode>200</statusCode>
    </batchQueryPartResponse>
  </batchPartResponse>

 

 

Assigned Tags

      45 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hey Sana,

      Well explained. Thanks for the detailed explanation with appropriate screenshots.

      Thanks,

      Ganga.

      Author's profile photo Mark Bernabe
      Mark Bernabe

      Hi Sana,

      Thanks for the well explained blog! One thing we've noticed with the Batch Request is its performance. It is really slow compared to a normal OData request. For example, when creating Interactions and Interaction Contacts from external system, we use CUAN_IMPORT_SRV OData service. In the File based load - Interactions iFlow inside the SAP Hybris Marketing Cloud - file based data load package, Batch Request is used. However, it seems that we can also achieve the same results by just using the normal ImportHeader instead of Batch processing. In addition, it is a lot faster.

      So when is Batch Request recommended over the normal ImportHeaders and vice versa specifically for CUAN_IMPORT_SRV?

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Mark,

      Thank you for your comment. From what I know, ImportHeader was added 3 years ago when batch was not available, it works by internally using deep insert. I also checked with Hybris colleagues and added a new example to this blog [Scenario 3: Batch Request with multiple entries in one ChangeSet] which would considerably improve the performance of batch calls.

       

      I am not an expert in SAP Hybris Marketing services but some differences that I could notice with service 'CUAN_IMPORT_SRV' are

      Batch ImportHeader
      Batch- POST call Deep Insert Operation- POST Call
      Can be used with all entities defined in the metadata Can only be used with entities 'Contacts' and 'Interactions' (navigations as defined in the metadata)
      Create,Merge,Update,Delete operations supported Only Create supported

      i would not be able to comment on the performance with ImportHeader but if you have huge chuck of data to be loaded, batch would be the suggested approach.

      For smaller data, as you mentioned Import Header might be better.

      Author's profile photo Mark Bernabe
      Mark Bernabe

      Hi Sana,

      Thanks for taking the time to answer my question. It's really helpful and greatly appreciated. With regards to the performance, I think it's the other way around. For huge volume of data, ImportHeader is faster compared to using BatchRequest. From our tests, a batch of 30k Interactions and Contacts only took 4 mins to complete with ImportHeader as compared to using Batch that took more than 2 hours. Moreover, most of the time it fails because of timeout error.

      Author's profile photo Marcus Englert
      Marcus Englert

      Hi Sana,

      thank you for your post, it's very helpful!

      I tried a similar scenario, but the call of the OData service fails with HTTP 400 - bad request

      com.sap.gateway.core.ip.component.odata.exception.OsciException:  : 400 : HTTP/1.1
      
      OData Method             :   BATCH
      Request URI              :   POST https://*****.hana.ondemand.com/service/odata.srv/$batch HTTP/1.1
      Request Headers          :   
        Authorization            : Basic ********
        Content-Type             : multipart/mixed;boundary=batch
        x-csrf-token             : ********
        Cookie                   : JSESSIONID               = COULD_NOT_BE_RESOLVED; Path=/service; Secure; HttpOnly;
                                   JTENANTSESSIONID_a3bb64753= ********;
                                    Domain                  = ********; Path=/; Secure; HttpOnly;
                                   BIGipServer*****.hana.ondemand.com= ********; path=/; httponly; secure;
      
      HTTP Status Line         :   HTTP/1.1 400 
      Response Headers         :   
        DataServiceVersion       : 1.0
        Date                     : Tue, 30 Jan 2018 12:13:31 GMT
        Content-Type             : application/xml
        Content-Length           : 213
        X-Cnection               : close
        Server                   : SAP
        Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
      , cause: com.sap.gateway.core.ip.component.odata.exception.OsciException:  : 400 : HTTP/1.1

      Now I found the problem, it's because of the line feed in the batch request, the CPI creates the body of the batch request only with line feed (LF), but the OData server expects carriage return and line feed (CRLF). Do you know if there's a possibility to change the request from LF to CRLF?

      Thank you for your help!

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Marcus,

      As of now we do not have any such mechanism. Could you please raise a ticket on component, LOD-HCI-PI-GB so that we can analysis this further.

       

      Author's profile photo Saranya Baskaran
      Saranya Baskaran

      The batch request body has LF as line separator by default.

      To change the request with CRLF, the property "SAP_BatchLineSeparator" has to be set with value "CRLF".

      Author's profile photo Marcus Englert
      Marcus Englert

      Thank you very much Saranya!

      I added the exchange property "SAP_BatchLineSeparator"  with CRLF and now it's working! 🙂

      Author's profile photo Anuj Dulta
      Anuj Dulta

      Hey Saranya,

       

      Can we set the same for SFTP Adapter as well?

      I am sending a file to SFTP server which wants PGP Encrypted and ‘ASCI Armoured’, with each line ending with CRLF.

      If I add the PGP Encryption, I end up getting the error:

      Linux/Unix/MAC OSX text transfer contained a CR character

      Any suggestions?

      Author's profile photo Saranya Baskaran
      Saranya Baskaran

      Hi Anuj,
      The above-mentioned property “SAP_BatchLineSeparator” is only meant for OData Receiver adapter. For SFTP, you may have to find the relevant documentation.

      Author's profile photo Hari Sonnenahalli
      Hari Sonnenahalli

      Sana-

       

      Hope all is well. I have a question regarding using OData operation to perform a delete operation before posting the data to HANA database. The scenario is I am making an API call and posting the data to HANA after exposing it as OData service. I am using a timer to do GET functions but I need to delete the records for the same entity list before GET function. How can I use ODATA adapter to perform this action? Any taught?

       

      Thanks for the support.

      Regards

       

      HS

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Hari,

      You will have to perform a GET to receive all the current entities and then you can perform a batch delete with all the available keys. Then you can POST all the new data.

      Author's profile photo Cesar Mejia
      Cesar Mejia

      Dear Sana

       

      Thanks for the explanation, its very nice.

       

      I have a issue related.

      My scenario is: Read a JON file from sFTP server and call a Odata service to Post Interactions.  (I know Convert JSON to XML format have troubles and we need a grovvy to ajust the JSON, but doesnt matter because I request the JSON should be as HCI needs)

       

       

      The JSON file example is:

      {
      "Interactions": [{
      "Interaction": [{
      "InteractionContactOrigin": "SAP_HYBRIS_CONSUMER",
      "InteractionContactId": "92a2fc8549a4ad28",
      "CommunicationMedium": "ONLINE_SHOP",
      "InteractionType": "SHOP_ITEM_VIEW",
      "InteractionTimeStampUTC": "1970-01-18T17:14:48",
      "InteractionAmount": "0",
      "InteractionCurrency": "EUR",
      "DeviceType": "Smartphone",
      "SourceSystemType": "iOS 11.3",
      "InteractionProducts": [{
      "InteractionProduct": [{
      "ProductOrigin": "SAP_HYBRIS_PRODUCT",
      "Product": "1288120"
      }]
      }],
      "InteractionProductCategories": [],
      "InteractionInterests": []
      }]
      }]
      }

      I already tested it in Postman successfully

       

       

      But in CPI , it finish with the following error:

      message : OSCI issue
      cause-exception : com.sap.gateway.core.ip.processor.exception.ODataProcessingException
      cause-message : OSCI issue
      class : java.util.ArrayList
      required-type : java.util.ArrayList
      converter-type : com.sap.gateway.core.ip.processor.converter.ConverterXMLToList
      path : /batchParts/batchChangeSet/batchChangeSetPart/Interactions
      line number : 2
      version : null
      -------------------------------, cause: org.apache.olingo.odata2.api.edm.EdmSimpleTypeException: The metadata do not allow a null value.
      LastErrorModelStepId= MessageFlow_4
      Node = vsa4479707
      ProcessId = 30fc0a027688f4fd2d78c40052ab2523b73c1612

       

       

      Do you have any idea?

       

      Best Regards

      Cesar

       

       

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Cesar,

       

      The OData Adapter in CPI perform metadata validation with the request payload.

      Kindly check if something is nullable false in your Interactions metadata that is not mentioned in your request payload.

       

      Author's profile photo Alexandre Franco
      Alexandre Franco

      Hello Sana,

       

      Can this batch operation with Odata v2 Adapter be used as a mechanism to extract data from SuccessFactors?

       

      Thanks a lot,

      Alexandre

       

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Alexandre,

      As of now GET operation is not supported in batch with the OData V2 Adapter in CPI.

      Regards,
      Sana

      Author's profile photo pradyumna routray
      pradyumna routray

      Hi Sana,
      Could you please suggest how do I implement the batch when the receiver side is a SOAP service instead of OData V2 adapter?

      Thanks,
      Pradyumna

      Author's profile photo Seng Ping Gan
      Seng Ping Gan

      Hi Sana Faraz

       

      Is there a plan to make GET operation to be supported in batch with the OData V2 Adapter in CPI?

       

      Thanks

      SP

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Seng Ping Gan,

      Please contact my PO, deepak.govardhanrao.deshpande@sap.com who should be able to guide you with the requirement list.

       

      Regards,
      Sana

      Author's profile photo Seng Ping Gan
      Seng Ping Gan

      HI Sana Faraz , thanks. I have already contacted deepak.govardhanrao.deshpande@sap.com via email. Hopefully, he/she can looks into my request.

      Thanks

      SP

      Author's profile photo Deepak G Deshpande
      Deepak G Deshpande

      Hi Seng Ping Gan,

      The support for GET in OData V2 $batch support is in our product road map backlogs/pipeline, but currently unscheduled.

      We will notify (e.g. via such a blog) when this feature is enabled

       

      Thanks

      Deepak

      Author's profile photo Gaurav Agarwal
      Gaurav Agarwal

      Hi Deepak,

       

      Is GET ready for OData batch processing?

       

      Thanks & Regards,

      Gaurav Agarwal

      Author's profile photo Andrey Tkachuk
      Andrey Tkachuk

      Hi all!

      Is the GET already working? Since I have a error 500 on the response.

      Author's profile photo Ariel Martinez
      Ariel Martinez

      HI Sana,

       

      we need to call a $batch to create CuponCodes for a particular Cupon, the operation path is  /Coupons(guid'<Coupon UUID>')/to_CouponCode

      https://help.sap.com/viewer/0f9408e4921e4ba3bb4a7a1f75f837a7/1902.500/en-US/68d3553eeed247509af978bf8af8a1bc.html#loio68d3553eeed247509af978bf8af8a1bc__entity_CouponCodes

       

      I didn't find that this is something supported by the ODATA adapter... do you know if there is some workaround.

      Tried also to perform a call with the plain HTTP adapter but I'm facing the CRLF issue, the property SAP_BatchLineSeparator seems not to be working...

       

      Thanks for your help

      Author's profile photo Vipul Khullar
      Vipul Khullar

      For https adaptors, you can use "/r/n" while preparing the batch request in the groovy script. This will change line feed to CRLF instead of LF.

      Author's profile photo Ariel Martinez
      Ariel Martinez

      Made it work completing the method URI. Thanks !

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Good to hear!

      Author's profile photo Amuktha Mallepula
      Amuktha Mallepula

      Hi Sana Faraz ,

      I am facing issue while performing delete operation through batch processing.

      How to configure uri in key value pairs with entiy and the object to be deleted. As I can understand, for delete uri is mandatory.

      when I am directly configuring the object ID that I wanted to delete, I am facing 404 status not found though the object is available.

      Could you please suggest me here

      Regards,

      Amuktha

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Amuktha,

      The uri tag is to look like <EntitySetName(key)>, please enter key in its desired type

      Example: <uri>Categories(25)</uri>

      Author's profile photo Ashokkumar Duraisamy
      Ashokkumar Duraisamy

      Hello Sana Faraz,

      The above information is very useful. I have a query in this.

      I am connecting to Successfactors OData adapter with $batch for deletion of $links. But my response payload is not accepted by CPI and throws following exception.

      com.sap.gateway.core.ip.component.odata.exception.OsciException: while trying to invoke the method org.apache.olingo.odata2.api.edm.EdmEntitySet.getName() of a null object loaded from local variable ‘entitySet’, cause: java.lang.NullPointerException: while trying to invoke the method org.apache.olingo.odata2.api.edm.EdmEntitySet.getName() of a null object loaded from local variable ‘entitySet’

      My batch request:

      –batch Content-Type: multipart/mixed; boundary=changeset_9770de8c-b8e4-44f8-9fd8-0ae9d4a2dde6 –changeset_9770de8c-b8e4-44f8-9fd8-0ae9d4a2dde6 Content-Type: application/http Content-Transfer-Encoding: binary DELETE User(‘11534748’)/$links/matrixManager HTTP/1.1 Accept: application/atom+xml –changeset_9770de8c-b8e4-44f8-9fd8-0ae9d4a2dde6 Content-Type: application/http Content-Transfer-Encoding: binary DELETE User(‘11534795’)/$links/matrixManager HTTP/1.1 Accept: application/atom+xml –changeset_9770de8c-b8e4-44f8-9fd8-0ae9d4a2dde6– –batch–

      My batch response:

      –batch_77e19246-9934-4971-afd0-1882ceda0263 Content-Type: multipart/mixed; boundary=changeset_822a9dea-cfdb-41c9-9adc-01720af76f2b –changeset_822a9dea-cfdb-41c9-9adc-01720af76f2b Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 204 No Content DataServiceVersion: 1.0 Content-Length: 0 –changeset_822a9dea-cfdb-41c9-9adc-01720af76f2b Content-Type: application/http Content-Transfer-Encoding: binary HTTP/1.1 204 No Content DataServiceVersion: 1.0 Content-Length: 0 –changeset_822a9dea-cfdb-41c9-9adc-01720af76f2b–

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Ashok,

      We might need to have a relook at this scenario. Could you please create a ticket to component LOD-HCI-PI-GB and share further information.

       

      Thanks,

      Sana

      Author's profile photo Varun Khetan
      Varun Khetan

      Hi Sana,

      I am connecting from SAP PO system to S4 HANA OData adapter for using Service for Business Partner.

      Reference Link for SAP API Hub: - https://api.sap.com/api/API_BUSINESS_PARTNER/resource?tag=A_BusinessPartner&path=get_A_BusinessPartner&method=get&opId=get_A_BusinessPartner

      My requirement is to update following entities (A_BusinessPartner, A_AddressEmailAddress, A_AddressPhoneNumber, A_BusinessPartnerAddress) of this API_BUSINESS_PARTNER using batch mode.

       

      I am facing following problems in doing it.

      1. Using mode = PATCH in batchChangeSetPart.

      When I use this PATCH mode while forming the XML in PO, I get the following error in XPI Inspector.

       

      ---- Debugging information ----
      cause-exception     : java.lang.NullPointerException
      cause-message       : while trying to invoke the method com.sap.aii.adapter.lib.processor.util.ODataMethodEnum.ordinal() of a null object returned from com.sap.aii.adapter.lib.processor.util.ODataMethodEnum.getValueOf(java.lang.String)
      class               : java.util.ArrayList
      required-type       : java.util.ArrayList
      converter-type      : com.sap.aii.adapter.lib.processor.converter.ConverterXMLToList
      path                : /batchParts/batchChangeSet/batchChangeSetPart/A_BusinessPartner
      version             : 1.4.9
      -------------------------------
      [EXCEPTION]
      com.thoughtworks.xstream.converters.ConversionException:
      ---- Debugging information ----
      cause-exception     : java.lang.NullPointerException
      cause-message       : while trying to invoke the method com.sap.aii.adapter.lib.processor.util.ODataMethodEnum.ordinal() of a null object returned from com.sap.aii.adapter.lib.processor.util.ODataMethodEnum.getValueOf(java.lang.String)
      class               : java.util.ArrayList
      required-type       : java.util.ArrayList
      converter-type      : com.sap.aii.adapter.lib.processor.converter.ConverterXMLToList
      path                : /batchParts/batchChangeSet/batchChangeSetPart/A_BusinessPartner
      version             : 1.4.9

       

      Formed XML batch request: -

      <batchParts>

      <batchChangeSet>

      <batchChangeSetPart>

      <method>PATCH</method>

      <A_BusinessPartner>

      <A_BusinessPartnerType>

      <BusinessPartner>3XXXXXX</BusinessPartner>

      <BusinessPartnerCategory>1</BusinessPartnerCategory>

      <CorrespondenceLanguage>DE</CorrespondenceLanguage>

      <FirstName>Cegid Update SOAP UI Multi Part</FirstName>

      <LastName>Development</LastName>

      </A_BusinessPartnerType>

      </A_BusinessPartner>

      </batchChangeSetPart>

      <batchChangeSetPart>

      <method>PATCH</method>

      <A_AddressEmailAddress>

      <A_AddressEmailAddressType>

      <AddressID>29882</AddressID>

      <Person>29881</Person>

      <OrdinalNumber>1</OrdinalNumber>

      <EmailAddress>cegidMultiPart.test@HOMTAIL.com</EmailAddress>

      </A_AddressEmailAddressType>

      </A_AddressEmailAddress>

      </batchChangeSetPart>

      </batchChangeSet>

      </batchParts>

       

      1. Using mode = PUT in batchChangeSetPart.

      In this way only the A_BusinessPartner entity is updated and there is no updates performed on the A_AddressEmailAddress entity.

      XPI Inspector Batch Request: -

      HTTP_CLIENT : 1663 REQUEST:

      --batch
      Content-Type: multipart/mixed; boundary=changeset_4d95dc09-e14a-4b14-b7c5-10d4edea3035

      --changeset_4d95dc09-e14a-4b14-b7c5-10d4edea3035
      Content-Type: application/http
      Content-Transfer-Encoding: binary

      PUT A_BusinessPartner(BusinessPartner='300001797') HTTP/1.1
      Content-Length: 170
      Accept: application/json
      Content-Type: application/json

      {"BusinessPartner":"300001797","BusinessPartnerCategory":"1","CorrespondenceLanguage":"DE","FirstName":"Cegid Update SOAP UI Multi Part","LastName":"Development Request"}
      --changeset_4d95dc09-e14a-4b14-b7c5-10d4edea3035
      Content-Type: application/http
      Content-Transfer-Encoding: binary

      PUT A_AddressEmailAddress(AddressID='29882',Person='29881',OrdinalNumber='1') HTTP/1.1
      Content-Length: 107
      Accept: application/json
      Content-Type: application/json

      {"AddressID":"29882","Person":"29881","OrdinalNumber":"1","EmailAddress":"cegidMultiPart.test@HOMTAIL.com"}
      --changeset_4d95dc09-e14a-4b14-b7c5-10d4edea3035--
      --batch—

      Response: -

      HTTP_CLIENT : 1663 REPLY:

      --1A552DA1A9F94F28F40E9F342AF197710
      Content-Type: multipart/mixed; boundary=1A552DA1A9F94F28F40E9F342AF197711
      Content-Length:       437

      --1A552DA1A9F94F28F40E9F342AF197711
      Content-Type: application/http
      Content-Length: 71
      content-transfer-encoding: binary

      HTTP/1.1 204 No Content
      Content-Length: 0
      dataserviceversion: 2.0

      --1A552DA1A9F94F28F40E9F342AF197711
      Content-Type: application/http
      Content-Length: 71
      content-transfer-encoding: binary

      HTTP/1.1 204 No Content
      Content-Length: 0
      dataserviceversion: 2.0

      --1A552DA1A9F94F28F40E9F342AF197711--

      --1A552DA1A9F94F28F40E9F342AF197710—

       

      OData Adapter Configuration: -

      Operation: CREATE

      Resource Path: A_BusinessPartner

      Enable Batch Processing: True

       

      Thanks,

      Varun

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Varun,

      Could you please change the method name from PATCH to MERGE and let me know if the issue is reproducible.

       

      Regards,
      Sana

      Author's profile photo Varun Khetan
      Varun Khetan

      Hi Sana,

      Thank you for your response and advice.

      So I made the change to MERGE and executed the request, and now it works with this method. I can see in S4 HANA system all the entities in the batch were updated successfully.

       

      Now, I have an additional question regarding the Batch OData call.

      I am trying to give back the OData response to the sender system via the SynchronousResponse functionality of CONNECTIVITY ADD ON 1.0.

      But now the response PAYLOAD (SynchronousResponse) is not getting generated when the OData call is made as a Batch Request.

      I am getting below error.

      Returning to application. Exception: com.sap.engine.interfaces.messaging.api.exception.MessagingException: Error encountered while executing mapping: com.sap.aii.af.service.mapping.MappingException: Mapping failed in runtimeRuntime Exception when executing application mapping program com/sap/xi/tf/_SynchronousResponse_to_SynchronousResponse_; Details: com.sap.aii.mappingtool.tf7.IllegalInstanceException; Cannot create target element /ns0:SynchronousResponse. Values missing in queue context. Target XSD requires a value for this element, but the target-field mapping does not create one. Check whether the XML instance is valid for the source XSD, and whether the target-field mapping fulfils the requirement of the target XSD

       

      OData Response seen in XPI Inspector:  -

      HTTP_CLIENT : 1844 REPLY:

      HTTP/1.1 202 Accepted
      content-type: multipart/mixed; boundary=F9E7329592A933E4064745788A1D6F9D0
      content-length: 818
      dataserviceversion: 2.0
      sap-processing-info: ODataBEP=,crp=,st=,MedCacheHub=,codeployed=X,softstate=
      sap-server: true
      sap-perf-fesrec: 1215850.000000

       

      Is it possible in some way to give back the OData SynchronousResponse when the Batch request is made?

       

      Thanks,

      Varun

      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Varun,

      From the error it looks like the mapping step is failing while parsing the OData Batch Response.

      I would suggest you look at section ‘Understanding the Batch Response’ from this blog and make sure you XSD follows this format.

       

      Regards,

      Sana

      Author's profile photo Varun Khetan
      Varun Khetan

      Hi Sana,

      I created Batch Response XSD as described above in the blog and it worked.

      Thanks you for the guidance.

      Regards,

      Varun

      Author's profile photo Uwe Voigt
      Uwe Voigt

      Hi Sana,

      I use batch processing when replicating business objects from a legacy database to Commerce Cloud. If there is one single object within the batch that produces an error, e.g. 400 because a related object is not there, the entire transaction within the Commerce Cloud is rolled back but the OData adapter gets a 202 and the integration flow commits its transaction. From a business point of view this should not happen because the object replication failed.

      What do you think, is this the expected behavior and I shall parse the response in a groovy script to get the transaction rolled back correctly? Or isn't that something that should be done by the adapter?

      Regards,

      Uwe

      Author's profile photo Vinay Avva
      Vinay Avva

      Hi Sana,

      Does the CPI ODATA V2 Adapter supports below kind of Batch Request ?

      --batch_34fcd829-64e4-4139-b880-f24aa4ee9235
      Content-Type: multipart/mixed; boundary=changeset_a6a10db7-ee1c-4e55-ab6e-4e65a808c683
      
      --changeset_a6a10db7-ee1c-4e55-ab6e-4e65a808c683
      Content-Type: application/http
      Content-Transfer-Encoding: binary
      
      PUT StringParameters(Pid='XXXXXXXXXXX',Id='TimeZone')?user=Vinay HTTP/1.1
      Content-Length: 64
      Accept: application/json
      Content-Type: application/json
      
      {"Value":"America/Chicago","Pid":"XXXXXXXXXXX","Id":"TimeZone"}
      --changeset_a6a10db7-ee1c-4e55-ab6e-4e65a808c683--
      --batch_34fcd829-64e4-4139-b880-f24aa4ee9235--

      If yes then I’m trying to send the above and getting this Error

      com.thoughtworks.xstream.io.StreamException: , cause: org.xmlpull.v1.XmlPullParserException: only whitespace content allowed before start tag and not - (position: START_DOCUMENT seen -... @1:1)
      

      Upon checking the Stack Trace this what I found

      aca895fd2#na#na#na#na#writeTraceOutBodyMessageAndHeader There is no Out Body Message to trace|
      Author's profile photo Sana Faraz
      Sana Faraz
      Blog Post Author

      Hi Vinay,

      In OData V2 adapter, the batch request body is a simple XML as seen in this blog, the adapter internally configures it into the multipart body as used by you.

      If you wish to use the multipart body as it, please use HTTP adapter.

       

      Regards,
      Sana

      Author's profile photo Pavan G
      Pavan G

      Hi Vinay Avva

      Add 'SAP_BatchLineSeparator' constant and value as CRLF in exchange property of content modifier before ODataMapping.

      This resolved my issue.

      Regards,

      Pavan G

      Author's profile photo Siddarth Kumar
      Siddarth Kumar

      Hi , I am new to SAP need to send an ItemModel from hybris application to a url through CPI , making

      a POST request but not able to get which classes and extensions  are required for the same ,  I

      searched everywhere , is there any resource regarding this?   using CPI is a requirement

      any help?

      Author's profile photo Dinesh M
      Dinesh M

      Hi Sana,

      This is indeed very helpful.

      FEW queries,

      is there a way to restrict Number of records in a batch?

      And is it possible to send data dynamically(POST) to the ODATA API instead of using content modifier?

      Thanks,

      Dinesh

      Author's profile photo Alejandro Llinares
      Alejandro Llinares

      Hi Sana,

      Thanks for this very useful blog!

      I am trying to specify a couple of query options in the <uri> tag of a GET query request payload like this:

      <batchParts>
          <batchQueryPart>
              <method>GET</method>
              <uri>EmpJob?$top=1&$select=userId</uri>
          </batchQueryPart>
      </batchParts>

      Unfortunately, only the first query option is being accepted. When I specify a second query option I start getting errors about characters like "$" or "=" not being allowed as start of entity reference names. Here is an example:

      Error Details
      com.thoughtworks.xstream.converters.ConversionException:
      ---- Debugging information ----
      cause-exception : com.thoughtworks.xstream.io.StreamException
      cause-message :
      class : java.util.ArrayList
      required-type : java.util.ArrayList
      converter-type : com.sap.gateway.core.ip.processor.converter.ConverterXMLToList
      path : /batchParts/batchQueryPart/uri
      line number : 4
      version : not available
      -------------------------------, cause: org.xmlpull.v1.XmlPullParserException: entity reference names can not start with character '$' (position: START_TAG seen ...<uri>EmpJob?$top=1&$... @4:29)

      Is this a bug in the parser or am I doing something wrong?

      Best regards,

      Alejandro

      Author's profile photo Alejandro Llinares
      Alejandro Llinares

      Hi all,

      In case someone comes across the same issue as me...

      The solution is to escape the ampersand "&" by substituting it with an "&amp;" string in the uri tag.

      So, my example becomes:

      <batchParts>
          <batchQueryPart>
              <method>GET</method>
              <uri>EmpJob?$top=1&amp;$select=userId</uri>
          </batchQueryPart>
      </batchParts>

      Best regards and happy coding!

      Alejandro

      Author's profile photo Jyothi Thippseh
      Jyothi Thippseh

      Hi Sana,

       

      Can you post examples on the batch delete operation as well ?