Skip to Content
Technical Articles

SAP Cloud Platform Backend service: Tutorial [8]: CDS : organize model (2): namespace and context

Thanks for dropping in todays tutorial.
I have to tell you in advance: it is useless.
So you can skip it is you’re not too interested.

To be honest: what you learn here doesn’t make any difference to the generated API and doesn’t provide any benefit for your end-user.

So what on earth do you write it?

Well, it helps to create beautiful and well-structured CDS models
Cool, I’ll read it

BTW, this blog is part of a series of tutorials explaining the usage of
SAP Cloud Platform Backend service in detail.

Today’s detail is about the possibility offered by CDS (Core Data and Services) to help structuring (big) models

There are 2 capabilities: Namespaces and contexts

In the previous tutorial, we’ve already learned what it means to have separate data model and service definition in a CDS file.

 

1. Namespace

Until now all our example models didn’t specify any namespace.

Example without namespace

We can define a simple model like this

service ProductService {

    entity ProductEntity{
        key productID : Integer;
        productName : String;
    }
}

After API generation we can check the Schema-section of the OData metadata document.

As you can see, the OData metadata document contains a Schema element which defines a Namespace.

This namespace is required because elements are referred by qualified name, which is shown in the screenshot.

Note:
An OData service can contain multiple Schemas. In OData V4, even foreign Schemas can be referenced.

However, our Backend service (currently) only supports one Schema

Note:
The value of Namespace attribute corresponds to the value of the “service” element in CDS

Note:
I’d like to repeat that “ProductEntity” is not a good entity-name in a CDS model. As you can see in the screenshot, “ProductEntity” is used as name of the EntitySet and the EntitySet name will be used to form the URL of the HTTP query request

Note:
Now let’s define a namespace in our CDS model and compare the result

Example with namespace

Like in programming languages, it is possible to define a namespace in order to organize a model.

Let’s repeat our very simple example, this time we add a namespace:

namespace com.company.businessapi;

service ProductService {
    entity ProductEntity{
        key productID : Integer;
        productName : String;
    }
}

 

I don’t see anything which would look organized better in this model…sorry

Yes, no.
However, let’s have a look at the OData-representation
In OData, the Schema-Namespace is now computed by concatenating the CDS-Namespace and the CDS-service name:

Note:
To be honest, using namespace makes more sense if there are multiple CDS files referring to each other

However, feeding the Backend service with more than one CDS file is (currently) not supported.

Note:
In CDS too, the namespace is used in order to refer to elements

Note:
Example in the next section.

 

Example with qualified naming

namespace com.company.businessapi;

entity ProductEntity{
    key productID : Integer;
    productName : String;
}

service ProductEntity{
    entity Products as projection on businessapi.ProductEntity;
}

 

After creating API in Backend service, the OData metadata look exactly the same:

<no screenshot necessary>

 

2. Context

Contexts can be used to further organize the structure of a model.

Let’s try to create a meaningful example

In this example, we want to define some entities to store data, as usual, but our company has different departments which we want to separate.
As such, we define 2 contexts: warehouse and crm (or whatever)
Also, we define another context with no semantic purpose, just to separate commonly used type definitions.
That’s it?
That’s it.
Last, we define a service which exposes the entites
That’s it?
That’s it.
Really?
Really.

Here’s the example:

namespace com.company.businessapi;

// context for type definitions
context reuseTypesContext {

    type priceDecimal : Decimal(9, 2);
    type averageDecimal : Decimal(11, 1);
    type limitDecimal : Decimal(6, 5);

    type AddressType {
        city : String;
        street : String;
        streetNumber : Integer;
    }
}

// context for warehousing
context warehouseContext {

    entity ProductEntity{
        key productID : Integer;
        productName : String;
        supplierCompanyName : String;
        supplierAddress : reuseTypesContext.AddressType;
    }

    // example for using simple type definitions
    entity PharmProductEntity {
        key id : String;
        orderPrice : reuseTypesContext.priceDecimal;
        sellingPrice : reuseTypesContext.priceDecimal;
        averageCount : reuseTypesContext.averageDecimal;
        toxLimit : reuseTypesContext.limitDecimal;
    }
}

// context for customer relation
context crmContext { 

    entity CustomerEntity {
        key id : String;
        name : String;
        contact : {
            homepage : String;
            email : String;
            address : reuseTypesContext.AddressType;
        };
    }    
}

// finally the service definition
service ProductService {
    entity Products as projection on businessapi.warehouseContext.ProductEntity; 
    entity PharmProducts as projection on businessapi.warehouseContext.PharmProductEntity;
    entity Companies as projection on businessapi.crmContext.CustomerEntity{
                          id as companyId,
                          name as companyName,
                          contact.address.city as companyHeadquarters // referring to inline custom type
    };
}

 

Looks nice, doesn’t it?

Like a dream

What effect does the context have?

1. If you refer to a type in a different context, you have to use qualified naming:

address : reuseTypesContext.AddressType;

2. In the service definition, you refer to the entity via namespace plus context:

entity Products as projection on businessapi.warehouseContext.ProductEntity;

3. The following snippet shows how to refer to a property in a custom type in a different context, used by inline defined custom type, and referred from a service definition

entity Companies as projection on businessapi.crmContext.CustomerEntity{
		. . . 
                contact.address.city as companyHeadquarters // referring to inline custom type
};

 

Thanks, but I wanted to ask: what effect does the context have on the final OData service?

I feared this question….Well… it has no effect at all
In OData, there’s no concept of organizing the metadata with “context” or anything similar.
As such, while translating to OData, all context structures are flattened.

 

Nested Contexts

The following example shows how contexts can be nested.

namespace com.company.businessapi;

context warehouseContext {
    context warehouseProductContext {
        entity ProductEntity{
            key productID : Integer;
            productName : String;
            supplier : String;
        }
    }

    context warehouseRelationsContext {
        entity CustomerEntity {
            key id : String;
            warehouseId : Integer;
            warehouseProductId : Integer;
            warehouseCountry : String;
        }
    }
}

context crmContext { 
    entity CustomerEntity {
        key id : String;
        name : String;
        contact : String;
    }    
}

service ProductService {
    entity Products as projection on businessapi.warehouseContext.warehouseProductContext.ProductEntity; 
    entity Customers1 as projection on businessapi.crmContext.CustomerEntity;
    entity Customers2 as projection on businessapi.warehouseContext.warehouseRelationsContext.CustomerEntity;
}

 

You can also see that elements in the data model are targeted by their qualified names. Which allows duplicate names, as long as the path is different.

The service definition takes care of exposing the entities. In the service definition the exposed entities need to have unique name, but they refer to duplicate names by fully qualified name

 

While translating to OData, only the names in the service definition are taken into account, as such no danger of name clash

See here:

 

Summary

This tutorial has teached you to organize your model by using namespace and contexts.

Such structure doesn’t have effect on the resulting OData service, but helps to create modularized models which can be quickly transformed, split etc

As such, hopefully the tutorial isn’t as useless as expected.
Thanks, not useless at all
Thanks, the first useful comment

 

Links

CDS namespaces in the SAP Help portal

 

Appendix

<useless>

 

 

 

 

 

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