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: 
avidD
Advisor
Advisor

In this part of the series on Graph – the new API for connecting to your business data – we address the concept of key mapping, which is the challenge of navigating between copies of the same business object, present in different business systems with different keys. Please refer to thInformation Map to see all parts of this series. The Graph documentation on the Help Portal provides an in-depth look at many of the concepts featured in this part.  

This is the seventh part in the Graph multi-part tutorial series. In part 3 - construct and explore a Business Data Graph you learned how you, as an administrator, can set up a Business Data Graph (BDG) that enables developers to access all data in your landscape without having to deal with different connection protocols, query languages, and API styles. For testing this part of the tutorial, you must have access to your own landscape that includes an SAP Sales Cloud and an SAP S/4HANA instance, which are integrated with Cloud Integration.

This part of the tutorial addresses an interesting challenge: navigating between copies of the same business object, present in different business systems with different keys. This is commonly the result of master data replication. For instance, some of the main attributes  a new business partner in an SAP S/4HANA system are copied by an integration process to another system, where the new copy is assigned a key from a different key range.

While each system serves different purposes and maintains different data details, client applications occasionally must access both copies in both systems. As an example, consider a list of products in which you want to show the status of each product, stored in SAP Sales Cloud, alongside its country of origin, stored in SAP S/4HANA.

In such cases, without Graph you must educate your client developers about all the different keys of all entities that exist in multiple systems and where to learn which keys identify the same objects. Your developers will then have to code the key lookups and further processing explicitly into their applications. This challenging task obviously has no relationship to the business problem they actually need to solve.

Graph hides the complexity of such cross-system navigations from developers via the configuration of key mapping. But before exploring how Graph solves the problem, we shall investigate the challenge and how developers must solve it when Graph is not used.

The problem: educating your developers to be data integration experts

Almost every enterprise landscape contains duplicate data objects. These are often objects like business partners (customers, partners, suppliers) or products. For instance, the same bicycle may be described in SAP S/4HANA with details about its manufacturer, and in SAP Sales Cloud, with information about how it is sold. At the same time, it is normal for different data sources to use different key ranges, and thus the same bicycle is identified with a different key in each system. Consequently, the developer task of getting a 360° view on the product details is highly complex because the developer must juggle with the different keys of the same object in different systems and manually dereference links between objects by joining data based on these cross-system references.

For our example, we shall assume a landscape with two destinations

    • s4h-product: an SAP S/4HANA Cloud tenant serving A_Product
    • c4c-odata: an SAP Sales Cloud tenant serving ProductCollection

In the landscape, we have set up Cloud Integration to replicate products from SAP S/4HANA to SAP Sales Cloud. Consequently, both destinations provide information about products. The products in SAP Sales Cloud don’t contain all the information that can be found in the SAP S/4HANA tenant. For instance, the attribute CountryOfOrigin may exist only in SAP S/4HANA. On the other hand, the copies in SAP Sales Cloud contain additional built-in attributes such as a StatusText field and may be further augmented with custom fields. Consider a particular product, the racing bike RB100. This product is identified in SAP Sales Cloud by two unique attribute values: ObjectID '999' and ProductID '789'. That same product is exposed by the SAP S/4HANA Product API with key Product 'xyz'.

objects-and-associations-my-bdg.png

Figure 1: Representations of the same product in one landscape

The developer is now tasked to build an application that displays all the information about selected products available in the landscape. To implement such a seemingly simple task, the developer must join the information about the product with key '999' in SAP Sales Cloud with the information with key 'xyz' in SAP S/4HANA.

However, how can they know that 'xyz' in SAP S/4HANA describes the same product as '999' in SAP Sales Cloud? There are many ways in which such relationships are established in practice. One common pattern, in particular when using SAP Sales Cloud, is the use of a dedicated attribute to store a reference from objects in SAP Sales Cloud to objects outside of SAP Sales Cloud. In our case, the ProductCollection instance with ObjectID ‘999’ has another attribute, ExternalID, with the value ‘xyz’, establishing the (equality) relationship to the corresponding A_Product instance ‘xyz’ in SAP S/4HANA. Maintaining the values of this attribute for all products is the responsibility of the integration which was set up with Cloud Integration.

Consequently, to get a 360° view of our bicycle RB100 given its ID in SAP S/4HANA, the developer must execute two queries:

…/API_PRODUCT_SRV/A_Product('xyz')
…/c4codata/ProductCollection?$filter=ExternalID eq 'xyz'

When the application user navigates another reference to the same object, but starting with an ID from SAP Sales Cloud, then first, the following request must be constructed and executed against SAP Sales Cloud:

…/c4codata/ProductCollection('999')

Then, the developer must extract the value of the ExternalID attribute, namely ‘xyz’, from the result of this query. Finally, the developer must construct another request for the A_Product instance with that key:

…/API_PRODUCT_SRV/A_Product('xyz')

When the developer wants to do a filter query to select the data for a whole page of products in the app, they must concatenate strings to produce a long $filter-condition about ExternalID values. Then, when receiving the result, they must do a join inside the extension application to marry the different records from SAP S/4HANA to their counterparts from SAP Sales Cloud. This is a tedious, repetitive, and error-prone task. Further, implementing a relational join in an extension application obviously has nothing to do with the business problem to be solved, which is to show all data about products.

However, the biggest problem with this approach is that to be able to construct all these queries, the developer must in the first place know of this reference being modeled via the ExternalID attribute. To make things even worse, such external key attributes are just a pattern for integrating enterprise systems, but the external key attributes have different names in different entities and systems. This presents a major obstacle for the task of implementing a supposedly simple 360° view on distributed objects.

Graph to the rescue

Wouldn’t it be nice if you, as an administrator of Graph, could declare such cross-service references once and for all and then developers could just remain ignorant about these complications and navigate transparently along associations between the different representations of the products, for all applications?

We shall now explore how exactly this is achieved with Graph. The first step will be to configure a BDG that pulls its data from the two given data sources.

As an administrator you configure these two data sources:

    • mySC: an SAP Sales Cloud tenant serving ProductCollection
    • myS4: an SAP S/4HANA tenant serving A_Product

We can use the Graph functionality of SAP Integration Suite to generate a configuration for our landscape. We shall rename the BDG and the data sources in the generated configuration. The following listing shows our generated BDG configuration with a few manual adaptations marked in blue.

{ "businessDataGraphIdentifier": "my-bdg",
  "graphModelVersion": "1.0.0",
  "dataSources": [
    { "name": "mySC", "services": [{ "destinationName": "c4c-odata" }] },
    { "name": "myS4", "services": [{ "destinationName": "s4h-product" }] }
  ],
  "locatingPolicy": {
    "rules": [
      { "name": "sap.s4.*", "leading": "myS4" },
      { "name": "sap.c4c.*", "leading": "mySC" },
      { "name": "sap.graph.*", "leading": "myS4", "local": ["mySC"] }
    ]

  }
}

Listing 1: Initial BDG configuration

Please refer to part 3 of the tutorial - Construct a Business Data Graph to see how to generate and activate the above BDG configuration.

Graph exposes data from the underlying data sources in different system-specific namespaces of our Business Data Graph. Entities from SAP S/4HANA instances are exposed in the sap.s4 namespace, whereas entities from SAP Sales Cloud instances are exposed in the sap.c4c namespace. Furthermore, there is another namespace, called sap.graph, which exposes select entity types and their attributes in a unified and simplified form. We shall use this namespace as the entry point to the graph. In our example, there is an A_Product object ‘xyz’ in myS4 (SAP S/4HANA) and a ProductCollection object ‘999’ in mySC (SAP Sales Cloud) Lastly, there is an sap.graph/Product with displayId ‘xyz’, which is a virtual view on the A_Product in SAP S/4HANA. The following figure depicts these objects as nodes in a graph with associations as edges.

2_dangling-asociation.png

Figure 2: Objects and associations in my-bdg

As you can see, the sap.graph/Product view has associations to the two system-specific representations of the same product. The sap.graph/Product's association _s4 points to the corresponding A_Product, because myS4 is configured as the leading system for all sap.graph entities in my-bdg. Thus, the system-specific representation in SAP S/4HANA can be reached by navigating from the sap.graph/Product along this dedicated association or by expanding the association.
Likewise, the sap.graph/Product has the association _c4c because mySC is defined as having local copies of sap.graph entities. However, it looks like the _c4c association is a “dangling pointer” into the void. We shall try out our BDG with some example queries to see what’s going on. First, we execute the following query to retrieve a (short) list of sap.graph products along with their S/4-representations:

…/my-bdg/sap.graph/Product?$top=1&$expand=_s4($select=Product,CountryOfOrigin)

For the sake of simplicity, we assume that our example product is the first result in the response. Consequently, this request will result in the racing bike RB100 as a sap.graph/Product with displayID 'xyz', and populated with data from myS4, which is the leading system as configured by our locating policy. Nested into it, we find the sap.s4/A_Product instance that represents the very same object with the additional property CountryOfOrigin.

{ "@odata.context": "$metadata#Product(_s4(Product,CountryOfOrigin))",
  "value": [
    { "id": "myS4~xyz",
      "displayId": "xyz",
      "name": "RB100",
      "_s4": {
        "Product": "xyz",
        "CountryOfOrigin": "DE"
      }
}]}

Listing 2: Result of a list query against the sap.graph/Product

Of course, the developer would like to get the information about the same product that is stored only in mySC in the same way. That is the ProductCollection instance with ObjectID ‘999’. The developer can expect to get this data by expanding the _c4c association as in the following query

…/my-bdg/sap.graph/Product?$top=1&
    $expand=_s4($select=Product,CountryOfOrigin),_c4c($select=StatusText)

However, as we saw in figure 2, there is no connection from the sap.graph/Product to the sap.c4c/ProductCollection. Therefore, this query will result in a HTTP 404 error. The reason is that without any further configuration, the dereferencing of the _c4c association will result in the lookup of the sap.c4c/ProductCollection with ObjectID ‘xyz’, which does not exist.

The solution is to define a key mapping for the system-specific entity types. To do so, we modify our BDG configuration as follows (changes in blue):

{ "businessDataGraphIdentifier": "my-bdg",
  "graphModelVersion": "1.0.0",
  "dataSources": [
    { "name": "mySC", "services": [{ "destinationName": "c4c-odata" }] },
    { "name": "myS4", "services": [{ "destinationName": "s4h-product" }] }
  ],
  "locatingPolicy": {
    "keyMapping":[
      { "foreignKey": {
          "dataSource":"mySC",
          "entityName":"sap.c4c.ProductCollection",
          "attributes":[ "ExternalID" ] },
        "references":{
          "dataSource":"myS4",
          "entityName":"sap.s4.A_Product",
          "attributes":[ "Product" ]
        }
      }

    ],

    "rules": [
      { "name": "sap.s4.*", "leading": "myS4" },
      { "name": "sap.c4c.*", "leading": "mySC" },
      { "name": "sap.graph.*", "leading": "myS4", "local": [ "mySC" ] }
    ]

  }
}

Listing 3: BDG configuration with key mappings

This new BDG configuration is almost the same as the previous one. It only adds a foreign key constraint between sap.c4c/ProductCollection in data source mySC and sap.s4/A_Product in data source myS4. You may notice that this format of the referential constraint is inspired by foreign keys in SQL databases.

Graph will interpret this constraint when queries access the entities via appropriate associations. In our example, when accessing an sap.c4c/ProductCollection instance with a reference from myS4 (the qualifier in the ID is myS4) or vice versa, when accessing an sap.s4/A_Product with a reference originating from mySC (the qualifier in the ID is mySC), then Graph will use the ExternalID attribute of the ProductCollection to find the associated object.

Now, this configuration enables Graph to transparently respond to the Graph developer’s query, repeated here:

/my-bdg/sap.graph/Product?$top=1&
    $expand=_s4($select=Product,CountryOfOrigin),_c4c($select=StatusText)

The result of this query is the sap.graph representation of the product RB100 with both its system-specific representations nested into it.

{ "@odata.context":
  "$metadata#Product(_s4(Product,CountryOfOrigin),_c4c(StatusText,ObjectID))",
  "value": [
    { "id": "myS4~xyz",
      "displayId": "xyz",
      "name": "RB100",
      "_c4c": {
        "ObjectID": "999",
        "StatusText": "Active"
      },
      "_s4": {
        "Product": "xyz",
        "CountryOfOrigin": "DE"
      }
    }
  ]
}

Listing 4: 360° view on Product 'xyz'

The Graph developer can now execute a single query to get a true 360° view on the product including all the available information. It is not necessary to think about joins between multiple result sets in the extension application. What’s best, the developer does not even have to know or care how the equality of the different objects is determined; they just navigate along the edges of the graph. The complexity has been moved from the extension applications into Graph. This reduces the complexity of applications that cross system borders. Consequently, the developer can now fully focus on the business requirements.

Effectively, the entities and associations now look like this.

3_intact-association.png

Figure 3: objects and associations in my-bdg with cross-service edges enabled by key mapping

The sap.graph/Product now has an edge to each of its representations regardless of the source system.

Navigation between unified entities

Assume now, we want to always populate instances of sap.graph.SalesQuote with data from our SAP SalesCloud tenant mySC. This can be achieved by adding the locating rule

{ "name": "sap.graph.SalesQuote", "leading": "mySC" }

With this rule, when navigating to a sap.graph.Product from a SalesQuote in mySC with a request like

…/my-bdg/sap.graph/SalesQuote/1/items/10/?$expand=_product

Graph will populate both, the sap.graph.SalesQuote and the sap.graph.Product, with data from mySC because _product is retrieved with a reference from the SalesQuote in mySC which is listed in the local list of sap.graph.*.

As a final variant, assume we want to force sap.graph.Products to be populated with data from myS4, even when navigating from a sap.graph.SalesQuote in mySC. To achieve this, we add the following rule for the sap.graph.Product

{ "name": "sap.graph.Product", "leading": "myS4" }

In this rule, mySC is missing from the local list. This forces the sap.graph.Product to be populated from myS4. Because we defined a corresponding foreign key between the sap.c4c.ProductCollection and the sap.s4.A_Product, the same query will now return a sap.graph.SalesQuote with id 1 in mySC but with a nested sap.graph.Product retrieved from myS4. Thus, foreign keys are also interpreted when navigating between unified entities.

Summary

Key mapping removes the burden of merging different representations of the same data from the API clients, that is the extension applications. The knowledge about key mapping is moved into the locating policy in the configuration of the Business Data Graph where it is declared once for all clients. Graph takes care of the developers by executing the complex key translation logic of their requests against the BDG. Consequently, extension application developers can focus on the business requirements and don't have to be data integration experts at the same time.

Key mapping in Graph thus creates new edges on the data level of the BDG and, in doing so, it enables a 360° view on the very same real-world objects despite different identifiers being used for the same objects in disparate data sources.


David Kensche, Development Architect and Engineering Lead (Runtime) – Graph in SAP Integration Suite 

Learn more about Graph in the SAP Community