How to implement
Deep Insert
in
SAP Cloud Application Programming Model
with deep insert on remote service
Quicklinks:
Project Files
Part 1: Intro
Part 2: UUID
Part 3: Multi-Level
Part 5: using SDK

entity OrderEntity {
. . .
linkToItems : Composition of many ItemEntity
on linkToItems.linkToOrder = $self;
}
entity ItemEntity {
. . .
linkToOrder : Association to OrderEntity;
}@cds.persistence.skip
entity OrderEntity as projection on relation.OrderEntity;@Create(entity = "OrderEntity", serviceName = "RelationService")
public CreateResponse createSalesOrder(CreateRequest createRequest) 
// 1) access the payload from request body, which is OData V4
Map<String, Object> v4RequestMap = createRequest.getData().asMap();
// 2) compose the payload to be sent to remote OData V2 service
Map<String, Object> v2RequestMap = convertV4RequestPayloadToV2(v4RequestMap);
// 3) send request to v2 service
Map<String, Object> v2ResponseMap = ODataCreateRequestBuilder
.withEntity("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC", "SalesOrderSet")
.withBodyAsMap(v2RequestMap)
.build()
.execute("ES5Destination")
.asMap();
// 4) convert v2 response back to v4
Map<String, Object> v4ResponseMap = convertV2ResponsePayloadToV4(v2ResponseMap);
// 5) compose the V4 response of our service
return CreateResponse.setSuccess().setData(v4ResponseMap).response();Map<String, Object> v4RequestMap = createRequest.getData().asMap();Map<String, Object> v2RequestMap = new HashMap<String, Object>();v4RequestMap.get("commentOnOrder")v2RequestMap.put("Note", v4RequestMap.get("commentOnOrder"));v2RequestMap.put("CurrencyCode", "USD");List<Map<String, Object>> v4InlineItemsList = (List<Map<String, Object>>)v4RequestMap.get("linkToItems");Map<String, Object> v2ResponseMap = ODataCreateRequestBuilder
.withEntity("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC", "SalesOrderSet")
.withBodyAsMap(v2RequestMap)
.build()
.execute("ES5Destination")
.asMap();return CreateResponse.setSuccess().setData(v4ResponseMap).response(); - name: ES5Destination
properties:
url: https://sapes5.sapdevcenter.com
username: your_ES5_username
password: your_ES5_password - name: ES5Destination
group: destinations
properties:
name: ES5Destination
url: '~{url}'
username: '~{username}'
password: '~{password}'| HTTP Verb |
| POST |
| URL |
| https://p123trial-acc-space-deepinsertremote.....odata/v2/RelationService/OrderEntity |
| Headers |
| Content-Type: application/json |
| Request body |
| { "commentOnOrder": "Want my laptops", "linkToItems": [ { "productForOrder": "HT-1001", "numberOfProductsInOrder": 11, } ] } |

namespace com.relation;
entity OrderEntity {
key orderId: String;
commentOnOrder: String;
linkToItems : Composition of many ItemEntity on linkToItems.linkToOrder = $self;
}
entity ItemEntity {
key itemId: UUID;
productForOrder: String;
numberOfProductsInOrder: Decimal(5, 2);
linkToOrder : Association to OrderEntity;
}
using com.relation from '../db/data-model';
service RelationService {
@cds.persistence.skip
entity OrderEntity as projection on relation.OrderEntity;
@cds.persistence.skip
entity ItemEntity as projection on relation.ItemEntity;
}package com.example;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cloud.sdk.odatav2.connectivity.ODataCreateRequestBuilder;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.service.prov.api.exception.DatasourceException;
import com.sap.cloud.sdk.service.prov.api.operations.Create;
import com.sap.cloud.sdk.service.prov.api.request.CreateRequest;
import com.sap.cloud.sdk.service.prov.api.response.CreateResponse;
import com.sap.cloud.sdk.service.prov.api.response.ErrorResponse;
public class ServiceImplementation {
@Create(entity = "OrderEntity", serviceName = "RelationService")
public CreateResponse createSalesOrder(CreateRequest createRequest) throws DatasourceException{
// 1) access the payload from request body, which is OData V4
Map<String, Object> v4RequestMap = createRequest.getData().asMap();
// 2) compose the payload to be sent to remote OData V2 service
Map<String, Object> v2RequestMap = convertV4RequestPayloadToV2(v4RequestMap);
try {
// 3) send request to v2 service
Map<String, Object> v2ResponseMap = ODataCreateRequestBuilder
.withEntity("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC", "SalesOrderSet")
.withBodyAsMap(v2RequestMap)
.build()
.execute("ES5Destination")
.asMap();
// 4) convert v2 response back to v4
Map<String, Object> v4ResponseMap = convertV2ResponsePayloadToV4(v2ResponseMap);
// 5) compose the V4 response of our service
return CreateResponse.setSuccess().setData(v4ResponseMap).response();
} catch (ODataException e) {
return CreateResponse.setError(ErrorResponse.getBuilder()
.setMessage(e.getMessage())
.setStatusCode(501)
.setCause(e)
.response());
}
}
/* REQUEST HELPERS */
// handle the full payload, the parent entity (SalesOrder) including nested inline list of children (LineItems)
private Map<String, Object> convertV4RequestPayloadToV2(Map<String, Object> v4RequestMap){
// map the v4 property names to v2 and, in addition, fill some non-nullable fields
Map<String, Object> v2RequestMap = new HashMap<String, Object>();
v2RequestMap.put("Note", v4RequestMap.get("commentOnOrder"));
v2RequestMap.put("CustomerID", "0100000000");
v2RequestMap.put("CurrencyCode", "USD");
// now handle the deep insert, the nested inline list of maps
List<Map<String, Object>> v4InlineItemsList = (List<Map<String, Object>>)v4RequestMap.get("linkToItems"); // to-many association
List<Map<String, Object>> v2RequestInlineList = convertV4InlineListToV2(v4InlineItemsList);
v2RequestMap.put("ToLineItems", v2RequestInlineList);
return v2RequestMap;
}
// inline list: SalesOrderLineItem collection
private List<Map<String, Object>> convertV4InlineListToV2(List<Map<String, Object>> v4InlineItemsList){
// the nested inline data is a list, because of to-many association
List<Map<String, Object>> v2InlineItemsList = new ArrayList<Map<String, Object>>();
// loop through all v4 line items in order to map them to v2
for (Map<String, Object> v4InlineMap : v4InlineItemsList) {
Map<String, Object> v2InlineMap = convertV4InlineMapToV2(v4InlineMap);
v2InlineItemsList.add(v2InlineMap);
}
return v2InlineItemsList;
}
// inline Map: single SalesOrderLineItem entry
private Map<String, Object> convertV4InlineMapToV2(Map<String, Object> v4InlineMap){
Map<String, Object> v2InlineMap = new HashMap<String, Object>();
v2InlineMap.put("DeliveryDate", new Date(System.currentTimeMillis())); // immediate delivery
v2InlineMap.put("ProductID", (String)v4InlineMap.get("productForOrder"));
v2InlineMap.put("Quantity", (BigDecimal)v4InlineMap.get("numberOfProductsInOrder"));
v2InlineMap.put("CurrencyCode", "USD");
v2InlineMap.put("ItemPosition", "0000000010");
return v2InlineMap;
}
/* RESPONSE HELPERS */
// response of V2 deep insert contains a SalesOrder with expanded list of LineItems
private Map<String, Object> convertV2ResponsePayloadToV4(Map<String, Object> v2ResponseMap){
Map<String, Object> v4ResponseMap = new HashMap<String, Object>();
v4ResponseMap.put("orderId", (String) v2ResponseMap.get("SalesOrderID"));
v4ResponseMap.put("commentOnOrder", (String) v2ResponseMap.get("Note"));
// the response of deep insert is a $expand
List<Map<String, Object>> v2ResponseInlineList = (List<Map<String, Object>>) ((List<Map<String, Object>>)v2ResponseMap.get("ToLineItems"));
// convert it to v4
List<Map<String, Object>> v4ResponseInlineList = convertV2InlineListToV4(v2ResponseInlineList);
// response of CREATE operation: the response body is composed by response of call to v2 service
v4ResponseMap.put("linkToItems", v4ResponseInlineList);
return v4ResponseMap;
}
private List<Map<String, Object>> convertV2InlineListToV4(List<Map<String, Object>> v2ResponseInlineList){
List<Map<String, Object>> v4ResponseInlineList = new ArrayList<Map<String, Object>>();
for(Map<String, Object> v2ResponseInlineMap : v2ResponseInlineList){
Map<String, Object> v4ResponseInlineMap = convertV2InlineMapToV4(v2ResponseInlineMap);
v4ResponseInlineList.add(v4ResponseInlineMap);
}
return v4ResponseInlineList;
}
// convert inline entry of V2 SalesOrderLineItem to V4 Map
private Map<String, Object> convertV2InlineMapToV4 (Map<String, Object> v2ResponseInlineMap){
Map<String, Object> v4ResponseInlineMap = new HashMap<String, Object>();
v4ResponseInlineMap.put("linkToOrder_orderId", v2ResponseInlineMap.get("SalesOrderID"));
v4ResponseInlineMap.put("itemId", UUID.randomUUID() );
v4ResponseInlineMap.put("productForOrder", v2ResponseInlineMap.get("ProductID"));
v4ResponseInlineMap.put("numberOfProductsInOrder", v2ResponseInlineMap.get("Quantity"));
return v4ResponseInlineMap;
}
}_schema-version: 2.0.0
ID: DeepInsertRemote
version: 1.0.0
modules:
- name: DeepInsertRemote-db
type: hdb
path: db
parameters:
memory: 256M
disk-quota: 256M
requires:
- name: DeepInsertRemote-db-hdi-container
- name: DeepInsertRemote-srv
type: java
path: srv
parameters:
memory: 990M
provides:
- name: srv_api
properties:
url: ${default-url}
requires:
- name: DeepInsertRemote-db-hdi-container
properties:
JBP_CONFIG_RESOURCE_CONFIGURATION: '[tomcat/webapps/ROOT/META-INF/context.xml:
{"service_name_for_DefaultDB" : "~{hdi-container-name}"}]'
- name: DeepInsertRemote-uaa
- name: ES5Destination
group: destinations
properties:
name: ES5Destination
url: '~{url}'
username: '~{username}'
password: '~{password}'
resources:
- name: DeepInsertRemote-db-hdi-container
type: com.sap.xs.hdi-container
properties:
hdi-container-name: ${service-name}
- name: DeepInsertRemote-uaa
type: org.cloudfoundry.managed-service
parameters:
service-plan: application
service: xsuaa
config:
xsappname: DeepInsertRemote-${space}
tenant-mode: dedicated
- name: ES5Destination
properties:
url: https://sapes5.sapdevcenter.com
username: your_ES5_username
password: your_ES5_password
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 36 | |
| 28 | |
| 27 | |
| 26 | |
| 26 | |
| 26 | |
| 25 | |
| 24 | |
| 23 | |
| 23 |