Defining Compositions in OData UI Services

Objectives

After completing this lesson, you will be able to:
  • Expose compositions to OData services.
  • Enable navigation in SAP Fiori elements apps.

Composition in Data Model Projection

Associations in CDS projection views

Just like the data definition of the composite RAP Business object consists of several CDS view entities, its projection consists of several CDS projection views, one projection view for each of the data definition views. To build an OData UI service, each projection view is enriched with the UI metadata, preferably in a CDS metadata extension.

To make the structure of the business object available in the OData Service too, you have to establish the hierarchy on the projection layer. To do so, you need compositions and to-parent associations that link the projection views.

Note

It is not sufficient to simply expose the associations defined in the underlying data definition views. The targets of those associations are a data definition views and not projection views. By following such an association, the consumer does not have access to the required metadata.
An example of redirecting associations

Instead of defining new associations on projection level, we recommend reusing the associations from the underlying data model and redirecting them to a new target.

In the example, the data model view on the left (Z00_R_Source), defines and exposes an association _Asso that uses the data model view on the right as its target (Z00_R_Target).

The view on the upper left (Z00_C_Source) is a projection on Z00_R_Source. It has access to the exposed association _Asso and can expose it further. However, when doing so, the association _Asso still points to the view on data model level (Z00_R_Target) and not, as it should do, to the projection view.

The association is redirected by adding a colon, the keyword redirected to, and the name of the new target.

Note

The redirected to keyword is only available in views that are defined with projection on. It is only supported if the new target is a projection of the original target.
Use redirected to <target> for compositions and to-parent associations

You can use redirected to <target> for any kind of association, that is, compositions, to-parent associations, and ordinary associations. However, when using redirected to <target>, the special characteristics of the compositions and to-parent associations are lost.

To solve this, ABAP CDS offers the dedicated syntax variants redirected to composition child and redirected to parent. By using these variants, the special characteristics of compositions and to-parent associations are kept.

When using redirected to composition child, the original association has to be a composition, and the new target has to be a projection of the original target. When using redirected to parent, the original association has to be a to-parent association.

Composition in Behavior Projection

Behavior projection of composite business object

To make the transactional behavior of the associations available in the OData service, you have to include it in the behavior projection. For this purpose, a use association statement exists, Quite similar to the use create, use delete, or use action statements.

If RAP draft handling is enabled in the behavior projection (use draft), the associations have to be draft enabled too, using the syntax addition with draft;.

Facets and Additional Object Page in SAP Fiori

Service definition for composite business object

If a RAP BO projection consists of several entities, each entity has to be exposed in the service definition explicitly to make the hierarchy available in the service.

Visualization of child entity in second facet

In an SAP Fiori elements app, the composition can be displayed by adding additional facets to the object page. The facet can then contain a list of the related child entity instances. In the example, the object page for the root entity Text contains a second facet, which displays a list of Text Lines.

UI metadata for second facet

The additional facet is defined in the metadata extension of the parent entity. The first facet, which was already there, has no value for thetargetElement sub annotation. Therefore, it displays the data of the parent entity itself. In the facet definition for the child entity, the targetElement sub annotation is filled with the name of an association. This association is used to derive the data and metadata for this facet.

The first facet is of type #IDENTIFICATION_REFERENCE. It displays the details for one instance of the root entity. The second facet is of type #LINEITEM_REFERENCE. It displays a list of child entity instances. #LINEITEM_REFERENCE is the usual choice when the association has a cardinality [0..*]. For associations with cardinality [0..1] or [1..1], you could also set the type to #IDENTIFICATION_REFERENCE, to display the details of a single instance on the facet.

Define the Composition in the OData UI Service

In this exercise, you add the child entity to the business object projection and the definition of the OData UI service. Then you add the relevant metadata to display the flight travel items in the service preview.

Note

In this exercise, replace ## with your group number.

Solution

Repository Object TypeRepository Object ID
CDS Data Definition (Projection, Child)/LRN/437E_C_TRAVELITEM
CDS Behavior Definition (Projection)/LRN/437E_C_TRAVEL
Service Definition/LRN/437E_TRAVEL
CDS Metadata Extension/LRN/437E_C_TRAVELITEM

Task 1: Copy Template for the Projection (Child Entity)

Create copies of the following repository objects and place them in your ABAP package. For the repository object names, take the name of the template and replace /LRN/D437T with Z##. Make sure that the copies refer to your own repository objects and not to the template objects.

Template

Repository Object TypeRepository Object ID
CDS Data Definition (Projection, Child)/LRN/437T_C_TRAVELITEM
CDS Metadata Extension/LRN/437T_C_TRAVELITEM

Steps

  1. Create a copy of data definition /LRN/437T_C_TRAVELITEM (suggested name: Z##_C_TravelItem).

    1. In the Project Explorer view, locate the /LRN/437T_C_TRAVELITEM data definition in the /LRN/S4D437_TEMPLATE package and right-click it to open the context menu.

    2. From the context menu, select Duplicate....

    3. Enter the name of your package and the name for the copy. Choose Next.

    4. Assign the new object to a transport request and choose Finish.

  2. Replace the selection target after the projection on keyword with the name of your own travel items view entity Z##_R_TravelItem and remove the root keyword.

    1. Adjust the code as follows:

      Code Snippet
      1234
      define view entity Z##_C_TravelItem provider contract transactional_query as projection on Z##_R_TravelItem {
  3. Activate the data definition.

    1. Press Ctrl + F3 to activate the development object.

  4. Create a copy of metadata extension /LRN/437T_C_TRAVELITEM (suggested name: Z##_C_TRAVELITEM).

    1. In the Project Explorer view, locate the /LRN/437T_C_TRAVELITEM metadata extension in the /LRN/S4D437_TEMPLATE package and right-click it to open the context menu.

    2. From the context menu, select Duplicate....

    3. Enter the name of your package and the name for the copy. Then choose Next.

    4. Assign the new object to a transport request and choose Finish.

  5. Replace the CDS view after the annotate view keyword with your own projection view for travel items Z##_C_TravelItem.

    1. Adjust the code as follows:

      Code Snippet
      12
      annotate view Z##_C_TravelItem with {
  6. Activate the data definition.

    1. Press Ctrl + F3 to activate the development object.

Task 2: Add Composition to the Data Model Projection

In the data definitions on projection level Z##_C_Travel and Z##_C_TravelItem, expose the associations from the underlying data model views. Make sure that the associations do not point at the views on data model level but that they are redirected to point at the respective views on projection level. Make sure that the associations keep their special character as composition and to parent association.

Steps

  1. Edit the data definition of your projection view for travel items Z##_C_TravelItem. At the end of the projection list, add the name of the to parent association, which you defined in the underlying view entity.

    1. Adjust the code as follows:

      Code Snippet
      123
      LocChangedAt, _Travel }
  2. Redirect the association to the projection view for flight travels.

    1. Adjust the code as follows:

      Code Snippet
      123
      LocChangedAt, _Travel : redirected to Z##_C_Travel }
  3. Classify the redirected association as a to parent association.

    1. Adjust the code as follows:

      Code Snippet
      123
      LocChangedAt, _Travel : redirected to parent Z##_C_Travel }
  4. Perform a syntax check.

    1. Press Ctrl + F2 and analyze the Problems view.

  5. Remove or comment the provider contract addition, then activate the data definition.

    1. Adjust the code as follows:

      Code Snippet
      123
      define view entity Z##_C_Travelitem as projection on Z##_R_TravelItem {
    2. Press Ctrl + F3 to activate the development object.

  6. Edit the data definition of your projection view for travels Z##_C_Travel. At the end of the projection list, add the name of the composition, which you defined in the underlying view entity.

    1. Adjust the code as follows:

      Code Snippet
      123
      LocChangedAt, _TravelItem }
  7. Redirect the association to the projection view for flight travel items and classify it as composition.

    1. Adjust the code as follows:

      Code Snippet
      123
      LocChangedAt, _TravelItem : redirected to composition child Z##_C_TravelItem }
  8. Activate the data definition.

    1. Press Ctrl + F3 to activate the development object.

Task 3: Add Composition to the Behavior Projection

Edit the behavior definition on projection level Z##_C_TRAVEL. Add a behavior projection for the child entity. Expose its etag definition and add the associations that establish the composition.

Steps

  1. Edit the behavior definition on projection level Z##_C_TRAVEL. At the end of the source code, use a code template to add a new define behavior statement for the child entity Z##_C_TravelItem.

    1. After the last closing bracket, add a new code row, enter def, and press Ctrl + Space to invoke code completion.

    2. From the suggestion list, choose defineBehaviorFor - Define Behavior For.

    3. Replace entity with Z##_C_TravelItem.

    4. Remove or comment the alias addition.

  2. Add the etag definition to the behavior projection.

    1. Adjust the code as follows:

      Code Snippet
      12345
      define behavior for Z##_C_TravelItem use etag { }
  3. For the child entity, add the standard operations update and delete to the projection.

    1. Adjust the code as follows:

      Code Snippet
      123456
      define behavior for Z##_C_TravelItem use etag { use update; use delete; }
  4. Add the to parent association _Travel to the behavior projection of the child entity and the composition_TravelItem to the behavior projection of the root entity.

    Note

    Do not forget to draft-enable both associations and create-enable the composition.
    1. Add the following code to the behavior definition for the root entity:

      Code Snippet
      1
      use association _TravelItem { create; with draft; }
    1. Adjust the behavior definition for the child entity as follows:

      Code Snippet
      12345678
      define behavior for Z##_C_TravelItem use etag { use update; use delete; use association _Travel { with draft; } }
  5. Activate the behavior projection.

    1. Press Ctrl + F3 to activate the development object.

Task 4: Add Composition to the OData UI Service

Add the child entity of your business object to your service definition Z##_TRAVEL and extend the UI metadata of the service to display a list of child entities in a second facet on the object page for flight travels.

Steps

  1. Open your service definition Z##_TRAVEL and add the projection view for flight travel items. Then activate the service definition.

    1. Adjust the code as follows:

      Code Snippet
      12345
      @EndUserText.label: 'Flight Travel Service Definition' define service Z##_TRAVEL { expose Z##_C_Travel; expose Z##_C_TravelItem; }
    1. Press Ctrl + F3 to activate the development object.

  2. Open your service binding Z##_UI_TRAVEL_O2 and analyze the information under Entity Set and Association.

    Note

    There is no Refresh button available in service bindings but you can press F5 to reload the service binding.
  3. Open the metadata extension for flight travels Z##_C_TRAVEL and locate the @UI.facet annotation. Inside the square brackets, add a comma (,) after the closing curly bracket and insert a copy of the existing facet definition.

    1. Adjust the code as follows:

      Code Snippet
      123456789101112
      @UI.facet: [ { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 }, { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 } ]
  4. Adjust the second facet definition according to the following table:

    PropertyValue
    id'TravelItem'
    purpose#STANDARD
    type#LINEITEM_REFERENCE
    label'Travel Items'
    position20
    1. Adjust the code as follows:

      Code Snippet
      123456789101112
      @UI.facet: [ { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 }, { id: 'TravelItem', purpose: #STANDARD, type: #LINEITEM_REFERENCE, label: 'Travel Items', position: 20 } ]
  5. Inside the second facet definition, add the property targetElement with the name of the composition as value.

    1. Adjust the code as follows:

      Code Snippet
      12345678910111213
      @UI.facet: [ { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 }, { id: 'TravelItem', purpose: #STANDARD, type: #LINEITEM_REFERENCE, targetElement: '_TravelItem', label: 'Travel Items', position: 20 } ]
  6. Activate the metadata extension and retest the preview for the OData UI service. Make sure that the object page for flight travels displays an (empty) list of flight travel items and that you can create new flight travel items.

    1. Press Ctrl + F3 to activate the development object.

    2. Open the service binding, place the cursor on the root entity and choose Preview....

    3. In the preview, display the details for one of the travels.

      Result

      The object page consists of two facets. The first facet shows the flight travel details and the second facet a list of the related flight travel items. This list is empty.
    4. Choose Edit to change to edit mode.

      Result

      On the second facet, you now see a Create button above the list of flight travel items.
    5. Choose Create and Apply to create a new travel item with initial values in all input fields.

      Result

      The list of travel items now contains one entry with initial values.
    6. Choose Save to save your changes.