Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
3,771

Introduction

As per the OData V2 specification, an OData Entry being created may contain links to other Entries in the service. If that is the case, the server is expected to create the inline Entry and the appropriate Links. For example, to create a new product in the catalog that is associated with the category Entry, you would execute a POST request against the OData.svc/Products collection with a product Entry containing a link to the Category Entry (using any URI that resolves to that resource).

Alternatively you can create and link an Entry to a related Entry by leveraging the addressing scheme if the server supports addressing related items. For example, if a server implements the OData URI conventions, the address …/Categories(10)/Products points at all the products in the specified category. When a POST request is issued against that products collection (instead of the top-level products collection), the server will create the new product Entry and automatically link it to the parent category.

You may combine the above two methods to create an Entry that is related to another one implicitly through the relationship implied in the URL, and related to other Entries by explicitly-specified Links in the request body. When you need to create multiple related Entries, you can do so as independent operations or perform a single POST with a tree of Entries (if the Links between Entries allow it structurally). The tree is formed by using inline expansion. All expanded Entries are considered new. Servers process a request with inline Entries by creating individual Entries and then linking them in the same way as linking would have happened in an independent request. The related Entry or collection of Entries is represented as the child element of an element.


For additional details refer the OData V2 links below:

http://www.odata.org/documentation/odata-version-2-0/operations/

http://www.odata.org/documentation/odata-version-2-0/uri-conventions/

http://www.odata.org/documentation/odata-version-2-0/atom-format/

Scenario

In HCI an OData service exposing a SOAP data source should be able to support deep insert operation on an entity in such a way that if the corresponding entity belonging to the SOAP service data model has a parent child relationship with another entity, then this should also get persisted along with the parent entity. There are certain prerequisites that defines the structural contract for the OData model and the SOAP service data model, which should be met and strictly followed to achieve the deep insert use case.

The edmx should look like



<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" Version="1.0">
    <edmx:DataServices m:DataServiceVersion="2.0">
        <Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm" xmlns:sap="http://www.sap.com/Protocols/SAPData" Namespace="Test">
            <EntityType Name="User">
                <Key>
                    <PropertyRef Name="userId"/>
                </Key>
                <Property Name="userId" Nullable="false" Type="Edm.String"/>
                <Property Name="address" Type="Edm.String"/>
                <Property Name="contactNo" Type="Edm.String"/>
                <Property Name="email" Type="Edm.String"/>
                <Property Name="userName" Type="Edm.String"/>
                <NavigationProperty FromRole="From_User" Name="ServiceSet" Relationship="Test.UserService" ToRole="To_Service"/>
            </EntityType>
            <EntityType Name="Service">
                <Key>
                    <PropertyRef Name="serviceID"/>
                </Key>
                <Property Name="serviceID" Nullable="false" Type="Edm.String"/>
                <Property Name="serviceName" Type="Edm.String"/>
                <Property Name="userID" Type="Edm.String"/>
            </EntityType>
            <Association Name="UserService">
                <End Multiplicity="1" Role="From_User" Type="Test.User"/>
                <End Multiplicity="*" Role="To_Service" Type="Test.Service"/>
                <ReferentialConstraint>
                    <Principal Role="From_User">
                        <PropertyRef Name="userId"/>
                    </Principal>
                    <Dependent Role="To_Service">
                        <PropertyRef Name="userID"/>
                    </Dependent>
                </ReferentialConstraint>
            </Association>
            <EntityContainer Name="default" m:IsDefaultEntityContainer="true">
                <EntitySet EntityType="Test.User" Name="UserSet"/>
                <EntitySet EntityType="Test.Service" Name="ServiceSet"/>
                <AssociationSet Association="Test.UserService" Name="UserServiceSet">
                    <End EntitySet="UserSet" Role="From_User"/>
                    <End EntitySet="ServiceSet" Role="To_Service"/>
                </AssociationSet>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>






Prerequisites

  1. There should be an association property defined between two OData entities
  2. There should be a one to many relationship cardinality defined between the two OData entities. This is also applicable for entities belonging to SOAP service data model.
  3. There should be a referential constraint defined between the two OData entities
  4. The web service API exposed for create operation should adhere to a nested inline structure format and return the parent entity structure as shown below:

Note: Deep Insert can be done up to any level, however the example below is a reference for only up to one level


Web Service API Input/Request Payload XML Format:


<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"

    xmlns:sei="http://sei.soap.service.metering.rt.gw.sap.com/">

    <soapenv:Header />

    <soapenv:Body>

        <sei:createSubscription>

            <!--Optional: -->

            <arg0>

                <!--Optional: -->

                <services>

                    <!--Zero or more repetitions: -->

                    <service>

                        <!--Optional: -->

                        <serviceID>1</serviceID>

                        <!--Optional: -->

                        <serviceName>getStockUpdates</serviceName>

                        <!--Optional: -->

                        <userID>1</userID>

                    </service>

                    <service>

                        <!--Optional: -->

                        <serviceID>2</serviceID>

                        <!--Optional: -->

                        <serviceName>purchaseStocks</serviceName>

                        <!--Optional: -->

                        <userID>1</userID>

                    </service>

                </services>

                <!--Optional: -->

                <user>

                    <!--Optional: -->

                    <address>Bangalore</address>

                    <!--Optional: -->

                    <contactNo>67867867</contactNo>

                    <!--Optional: -->

                    <email>user1@sap.com</email>

                    <!--Optional: -->

                    <userId>1</userId>

                    <!--Optional: -->

                    <userName>user1</userName>

                </user>

            </arg0>

        </sei:createSubscription>

    </soapenv:Body>

</soapenv:Envelope>

Web Service API Output /Response Payload XML Format:


<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

   <soap:Body>

      <ns2:createSubscriptionResponse xmlns:ns2="http://sei.soap.service.metering.rt.gw.sap.com/">

         <return>

            <address>Bangalore</address>

            <contactNo>67867867</contactNo>

            <email>user1@sap.com</email>

            <userId>1</userId>

            <userName>user1</userName>

         </return>

      </ns2:createSubscriptionResponse>

   </soap:Body>

</soap:Envelope>

In the iflow only 1 entity can be modelled. In this case it is UserSet. Hence we should have a script before request mapping to fetch list of services and place this value in header. We should also have a script after request mapping which combines the output from mapping and value that was stored in header in previous script. This will be the request payload for soap.




Request Mapping



Response Mapping


Script Before request Mapping


import java.lang.StringBuffer;
import java.lang.Class;
import com.sap.gateway.ip.core.customdev.logging.*;
import com.sap.gateway.ip.core.customdev.util.Message;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
def Message processData(Message message) {
    // Get the body from exchange
  Document payload = message.getBody();
  Node node = payload.getDocumentElement();
  processNodes(payload.getDocumentElement(), message);
  log.logErrors(LogMessage.TechnicalError, "message header1: "+  message.getHeaders().get("InlineEntry"));
   return message;
}
  def Message processNodes(Node node, Message message) {
  StringBuffer reqXML = new StringBuffer();
  NodeList nodeList = node.getChildNodes();
  for (int i = 0; i < nodeList.getLength(); i++) {
        Node currentNode = nodeList.item(i);
  if (currentNode.getNodeName() == "ServiceSet") {
  reqXML.append("<services>");
  NodeList nodeList1 = currentNode.getChildNodes();
  for (int j = 0; j < nodeList1.getLength(); j++) {
  Node odataEntryNode = nodeList1.item(j);
  if (odataEntryNode.getNodeName() == "Service") {
  reqXML.append("<service>");
  Node serviceNodeList = odataEntryNode.getChildNodes();
  for (int k = 0; k < serviceNodeList.getLength();k++) {
  Node serviceNode = serviceNodeList.item(k);
  if (serviceNode.getNodeName() == "userID") {
  reqXML.append("<userID>" + serviceNode.getTextContent() + "</userID>");
  } else if (serviceNode.getNodeName() == "serviceID") {
  reqXML.append("<serviceID>" + serviceNode.getTextContent() + "</serviceID>");
  } else if (serviceNode.getNodeName() == "serviceName") {
  reqXML.append("<serviceName>" + serviceNode.getTextContent() + "</serviceName>");
  }
  }
  reqXML.append("</service>");
  }
  }
  reqXML.append("</services>");
  } else {
  processNodes(currentNode, message);
  }
    }
  if (reqXML.toString() != null && reqXML.toString().length() > 0) {
  log.logErrors(LogMessage.TechnicalError, "reqXML: "+ reqXML);
  message.setHeader("InlineEntry", reqXML);
  log.logErrors(LogMessage.TechnicalError, "message header: "+ message.getHeaders().get("InlineEntry"));
  }
  return message;
}



Script after request mapping



import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.*;
import com.sap.gateway.ip.core.customdev.logging.*;
def Message processData(message) {
  String payload = new String(message.getBody(), "UTF-8");
  log.logErrors(LogMessage.TechnicalError, "payload in script2: "+payload);
    StringBuffer newReqXML = new StringBuffer();
    String inlineEntry = message.getHeaders().get("InlineEntry");
    log.logErrors(LogMessage.TechnicalError, "InlineEntry: "+inlineEntry);
    def tokens = payload.split("(?=<)|(?<=>)");
    log.logErrors(LogMessage.TechnicalError, "tokens: "+tokens);
    for(int i=0;i<tokens.length;i++) {
        log.logErrors(LogMessage.TechnicalError, "tokens: "+tokens[i]);
  newReqXML.append(tokens[i]);
        if(tokens[i].contains("</user>")){
            newReqXML.append(inlineEntry);
        }
    }
    log.logErrors(LogMessage.TechnicalError, "newReqXML: "+newReqXML.toString());
    message.setBody(newReqXML.toString());
    return message;
}


OData Request Payload


<entry xmlns="http://www.w3.org/2005/Atom"

    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"

    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"

    xml:base="https://localhost:8083/gateway/odata/SAP/MTR4;v=1/">

    <id>

        https://localhost:8083/gateway/odata/SAP/MTR4;v=1/UserSet('3')

    </id>

    <title type="text">UserSet</title>

    <updated>2015-09-11T19:14:22.678+05:30</updated>

    <category term="EXPAND.User"

        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

    <link href="UserSet('3')" rel="edit" title="User" />

    <link href="UserSet('3')/ServiceSet"

        rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ServiceSet"

        title="ServiceSet" type="application/atom+xml;type=feed">

        <m:inline>

            <feed xml:base="https://localhost:8083/gateway/odata/SAP/MTR4;v=1/">

                <id>

                    https://localhost:8083/gateway/odata/SAP/MTR4;v=1/ServiceSet

                </id>

                <title type="text">ServiceSet</title>

                <updated>2015-09-11T19:14:22.68+05:30</updated>

                <author>

                    <name />

                </author>

                <link href="UserSet('3')/ServiceSet" rel="self" title="ServiceSet" />

                <entry>

                    <id>

                        https://localhost:8083/gateway/odata/SAP/MTR4;v=1/ServiceSet(serviceID='5')

                    </id>

                    <title type="text">ServiceSet</title>

                    <updated>2015-09-11T19:14:22.681+05:30</updated>

                    <category term="EXPAND.Service"

                        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

                    <link href="ServiceSet(serviceID='5')" rel="edit" title="Service" />

                    <content type="application/xml">

                        <m:properties>

                            <d:serviceID>5</d:serviceID>

                            <d:userID>3</d:userID>

                            <d:serviceName>getStockHolderNames</d:serviceName>

                        </m:properties>

                    </content>

                </entry>

                <entry>

                    <id>

                        https://localhost:8083/gateway/odata/SAP/MTR4;v=1/ServiceSet(serviceID='6')

                    </id>

                    <title type="text">ServiceSet</title>

                    <updated>2015-09-11T19:14:22.682+05:30</updated>

                    <category term="EXPAND.Service"

                        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

                    <link href="ServiceSet(serviceID='6')" rel="edit" title="Service" />

                    <content type="application/xml">

                        <m:properties>

                            <d:serviceID>6</d:serviceID>

                            <d:userID>3</d:userID>

                            <d:serviceName>getNetWorth</d:serviceName>

                        </m:properties>

                    </content>

                </entry>

            </feed>

        </m:inline>

    </link>

    <content type="application/xml">

        <m:properties>

            <d:UserID>3</d:UserID>

            <d:UserName>user3</d:UserName>

            <d:ContactNo>324-5443-4353</d:ContactNo>

            <d:Email>user3@sap.com</d:Email>

            <d:Address>Chennai</d:Address>

        </m:properties>

    </content>

</entry>

OData Response Payload


<?xml version="1.0" encoding="utf-8"?>

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="http://localhost:8080/com.sap.gateway.core.gwcoreip.web/odata/SAP/MTR4;v=1/">

    <id>http://localhost:8080/com.sap.gateway.core.gwcoreip.web/odata/SAP/MTR4;v=1/UserSet('3')</id>

    <title type="text">UserSet</title>

    <updated>2015-09-24T13:23:02.103+05:30</updated>

    <category term="EXPAND.User" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"></category>

    <link href="UserSet('3')" rel="edit" title="User"></link>

    <link href="UserSet('3')/ServiceSet" rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ServiceSet" title="ServiceSet" type="application/atom+xml;type=feed"></link>

    <content type="application/xml">

        <m:properties>

            <d:UserID>3</d:UserID>

            <d:UserName>user3</d:UserName>

            <d:ContactNo>324-5443-4353</d:ContactNo>

            <d:Email>user3@sap.com</d:Email>

            <d:Address>Chennai</d:Address>

        </m:properties>

    </content>

</entry>

1 Comment