Skip to Content
Technical Articles

SAP Cloud Application Programming Model: Deep Insert (3) Multi-Level

Hello Syambabu Allu

How are you?

Hope you’re doing good and enjoying nice summer vacation.
Has been nice to receive your comment in my previous blog
I think we’re following each other already since many years…and it’s nice to see you’re still active and enthusiastic community member…😉
I’ve thought of writing you a letter to answer your question.

This has been your comment:

Great Blog on Deep Insert.Thank you for sharing this.

is that possible to create Multi-level deep insert using above approach.

Thank you,
Syam

First of all, thanks very much for your feedback!
I’d even say, thank you very much for it!
It is thanks to colleagues like YOU that encourage us to continue publishing and sharing findings…
Please continue with your generous words 😉

Now coming to your question: multi-level deep insert
I have good news for you:
Yes, my friend, it is possible.

I understand you and your necessities:
You have modelled a beautiful CDS which allows to navigate from one Entity to the next one:

entity CompanyEntity {
  . . .
  linkToContact  : Association to ContactEntity;
}

entity ContactEntity {
  . . .
  linkToCommunication  : Association to CommunicationEntity;
}

entity CommunicationEntity {
  . . .
  linkToComment : Association to CommentEntity;
}

entity CommentEntity {
  . . .
  message : String;
}

and now you want to create all nice data with one deep insert request, like this:

{
  "companyId": 1,
  . . . 
  "linkToContact": 
  {
    "contactId": 11,
    . . . 
    "linkToCommunication":
    {
      "communicationId": 111,
      . . . 
      "linkToComment": 
        {
          "commentId": 1111,
           . . . 

And you want to know whether it is possible?
I have good news for you…
The short answer is: yes
The friendly answer: yes my friend
The long answer: you just need to add more entries to the key map
The very long cryptic answer:

keyMap.put("linkToCommunication", Collections.singletonList("communicationId"));           
keyMap.put("linkToComment", Collections.singletonList("commentId"))

The extremely long and detailed and helpful answer:
OK, I can describe everything I did.
And for your convenience, my friend, I’ll attach all sample files to this letter 😉

Create Project

I’ve created a CAP project with name DeepInsertMulti
It has java package com.example and uses database and prefers OData version 2

CDS

I’ve used a little model which I’m attaching to this letter
And I’ve used a little service definition, also attached

Custom Java Code

Then I’ve overwritten the CREATE operation for the entity on which the multi-level deep insert is executed:

@Create(entity = "CompanyEntity", serviceName = "RelationService")
public CreateResponse createCompanyDeep(CreateRequest createRequest, ExtensionHelper extensionHelper) throws DatasourceException{

And I’ve created the required code like I described in my previous blogs here and here

As you know, the map is used by the framework to gather information about which is the key property for every entity to create
With other words, they CREATE payload contains multiple nested maps and for each map, an entry is created in the database and the FWK has to know which entity and which key field. So the map contains one entry for the top-level entity, where the key property is mapped to the entity itself

keyMap.put("CompanyEntity", Collections.singletonList("companyId"));        

For each nested map, I’ve created an entry where the key property is mapped to the Association

keyMap.put("linkToContact", Collections.singletonList("contactId"));                
keyMap.put("linkToCommunication", Collections.singletonList("communicationId"));           
keyMap.put("linkToComment", Collections.singletonList("commentId"));           

You know me, my friend, and as you know, I prefer to give names which make everything very clear. Thanks to this, the above example code makes clear what I described before: the names of entity and associations

See the full java class in the attachment of this mail.

MTA

Finally, I’ve done the 2 small modifications to the mta.yaml file, as described in previous blog

Deploy

Then I deployed the project

Test

After deployment, I checked the metadata document, to see if the 4 entities and the 4 navigation links looked as expected:
https://p123trial-subacc-space-deepinsertmulti-srv…/v2/RelationService/$metadata

Then I composed the request for a deep insert as follows:

HTTP Verb
POST
URL
https://p123trial-acc-space-deepinsertmulti-srv…/odata/v2/RelationService/CompanyEntity
Headers
Content-Type: application/json
Request body
{
“companyId”: 1,
“companyName”: “PetShop”,
“linkToContact_contactId”: 11,
“linkToContact”:
{
“contactId”: 11,
“contactName”: “Petty”,
“contactPhone”: 123456,
“linkToCommunication_communicationId”: 111,
“linkToCommunication”:
{
“communicationId”: 111,
“socialMedia”: “Facebook”,
“webAddress”: “www.facebook.com”,
“linkToComment_commentId”: 1111,
“linkToComment”:
{
“commentId”: 1111,
“message”: “very nice”
}
}
}
}

Afterwards, I was able to view the created entities in the 4 respective collections
And I was able to test the navigation
https://trial-acc-space-deepinsertmulti-srv…Service/CompanyEntity(1)/linkToContact
https://trial-acc-space-deepinsertmulti-srv…/ContactEntity(11)/linkToCommunication
https://trial-acc-space-deepinsertmulti-srv…/CommunicationEntity(111)/linkToComment

And the $expand on all nested navigation links
…<srv>/CompanyEntity?$expand=linkToContact/linkToCommunication/linkToComment

The screenshot points you to the result with the 3 nested inline entries

Is it this what you wanted to do?

I hope I have answered your question and it will help you with your endeavors
It has been interesting for me to try it out
BTW, you could have tried it yourself… 😉

I have to come to an end, as I’m running out of paper.
I wish you a nice and relaxing evening,
Have a nice time and good health for you and your beloved ones.
Good luck with all your requests
PS and good luck with CAP
PS and keep writing friendly comments…😉

Cheers,
Carlos

Attachments: Project Files

data-model.cds

namespace com.relation;

entity CompanyEntity {
  key companyId : Integer;
  companyName  : String;
  linkToContact  : Association to ContactEntity;
}

entity ContactEntity {
  key contactId : Integer;
  contactName : String;
  contactPhone : Integer;	
  linkToCommunication  : Association to CommunicationEntity;
}

entity CommunicationEntity {
  key communicationId : Integer;
  socialMedia : String;
  webAddress : String;
  linkToComment : Association to CommentEntity;
}

entity CommentEntity {
  key commentId : Integer;
  message : String;
}

cat-service.cds

using com.relation from '../db/data-model';

service RelationService {
    entity CompanyEntity as projection on relation.CompanyEntity
 	entity ContactEntity as projection on relation.ContactEntity; 
	entity CommunicationEntity as projection on relation.CommunicationEntity;   
	entity CommentEntity as projection on relation.CommentEntity;
}

ServiceImplementation.java

package com.example;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cloud.sdk.service.prov.api.EntityData;
import com.sap.cloud.sdk.service.prov.api.ExtensionHelper;
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;					

public class ServiceImplementation {
	
	@Create(entity = "CompanyEntity", serviceName = "RelationService")
	public CreateResponse createCompany(CreateRequest createRequest, ExtensionHelper extensionHelper) throws DatasourceException{
		// 1) retrieve the request payload, the data to create in backend
	    Map<String, Object> mapForCreation = createRequest.getData().asMap();
        		
        // 2) create map for each entity of deep insert: map key field to entity / resp. map key field to association
        Map<String, List<String>> keyMap = new HashMap<String, List<String>>();
        // Parent entity: CompanyEntity. Here, the key field is "companyId"       
        keyMap.put("CompanyEntity", Collections.singletonList("companyId"));        
        // For nested entity: assign the key field (contactId) of navigation target entity (ContactEntity) to the navigationProperty name (linkToContact) 
        keyMap.put("linkToContact", Collections.singletonList("contactId"));                
        // multi-level deep insert: continue navigation from ContactEntity to CommunicationEntity
        keyMap.put("linkToCommunication", Collections.singletonList("communicationId"));           
        // multi-level deep insert: continue navigation from CommunicationEntity to CommentEntity
        keyMap.put("linkToComment", Collections.singletonList("commentId"));           
        
        // 3) send data to database, including the info about keys 
        EntityData entityDataToCreate = EntityData.createFromDeepMap(mapForCreation, keyMap, "RelationService.CompanyEntity");
         // execute it in database
        EntityData result = extensionHelper.getHandler().executeInsertWithAssociations(entityDataToCreate, true);
        return CreateResponse.setSuccess().setData(result).response();
	}
}

 

 

mta.yaml

(to be used in trial account)

_schema-version: 2.0.0
ID: DeepInsertMulti
version: 1.0.0
modules:
  - name: DeepInsertMulti-db
    type: hdb
    path: db
    parameters:
      memory: 256M
      disk-quota: 256M
    requires:
      - name: DeepInsertMulti-db-hdi-container
  - name: DeepInsertMulti-srv
    type: java
    path: srv
    parameters:
      memory: 990M
    provides:
      - name: srv_api
        properties:
          url: ${default-url}
    requires:
      - name: DeepInsertMulti-db-hdi-container
        properties:
          JBP_CONFIG_RESOURCE_CONFIGURATION: '[tomcat/webapps/ROOT/META-INF/context.xml:
            {"service_name_for_DefaultDB" : "~{hdi-container-name}"}]'
      - name: DeepInsertMulti-uaa
resources:
  - name: DeepInsertMulti-db-hdi-container
    type: com.sap.xs.hdi-container
    properties:
      hdi-container-name: ${service-name}
  - name: DeepInsertMulti-uaa
    type: org.cloudfoundry.managed-service
    parameters:
      service-plan: application
      service: xsuaa
      config:
        xsappname: DeepInsertMulti-${space}
        tenant-mode: dedicated

 

Be the first to leave a comment
You must be Logged on to comment or reply to a post.