Skip to Content
Author's profile photo Jerry Wang

My CDS view self study tutorial – Part 5 how to create CDS view which supports navigation in OData service

The series of my CDS view blogs

So far we have a working CDS view ready for us to create a UI5 application on top of it via Smart Template in WebIDE within just a couple of minutes. Once done, the UI5 application will display the data from our CDS view like below. For step by step how to achieve this, please refer to this blog: Step by Step to create CDS view through SmartTemplate + WebIDE .


How is navigation implemented among CDS views

In this part, let’s create CDS view which supports node navigation in OData service. The previous CDS view we created has a flat structure which only have a root node. Now let’s create a series of CDS views:

1. A CDS view which contains two fields: spfli.connid and spfli.carrid. This view acts as the root node of the corresponding OData service model from semantic point of view. This view can support navigation from itself to the defined children node.

2. A CDS view which acts as the navigation target from previously defined “root” view. Besides the two fields from sflight.connid and sflight.carrid which correspond to the root view, it has additional new field sflight.fldate.

OData navigation means suppose currently I am in the context of spfli.connid = 0001 and spfli.carrid ( data record with yellow ), and through navigation I can get all its dependent data in red color. We will see how this navigation would be performed later.


3. A CDS view which exposes the two fields connid and carrid from root view and the associated data  from child view.

This view is called “consumption” view and used to published as OData service.

Source code of view #1:

@AbapCatalog.sqlViewName: 'zspfliroot'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'root view'
define view Zspfli_Root as  select from spfli
association [0..*] to Zsflight_Child as _Item on $projection.carrid = _Item.carrid
                                       and $projection.connid = _Item.connid
  key spfli.connid,
  key spfli.carrid,
  @ObjectModel.association.type: #TO_COMPOSITION_CHILD

Source code of view #2:

@AbapCatalog.sqlViewName: 'zsflightchild'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'child_view'
define view Zsflight_Child as select from sflight
association [1..1] to zspfli_root as _root
on $projection.connid = _root.connid
and $projection.carrid = _root.carrid
   key sflight.carrid,
   key sflight.connid,
   key sflight.fldate,
   @ObjectModel.association.type: [#TO_COMPOSITION_ROOT, #TO_COMPOSITION_PARENT]

Source code of view #3:

@AbapCatalog.sqlViewName: 'zflight_c'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'flight consumption view'
@OData.publish: true
@ObjectModel: {
   type: #CONSUMPTION,
define view Zflight_Com as select from Zspfli_Root {
  key Zspfli_Root.carrid,
  key Zspfli_Root.connid,
  @ObjectModel.association.type: [#TO_COMPOSITION_CHILD]

Activate all of these three CDS views. Since the third consumption view has annotation @OData.publish: true, once activated there will be an OData service automatically generated:


How to test navigation

First check the response from OData metadata request via url /sap/opu/odata/sap/ZFLIGHT_COM_CDS/$metadata in gateway client.

You should find two AssociationSets generated based on corresponding annotation in CDS views.


The entityset Zflight_Com has type Zflight_ComType, which has the navigation Property “to_Item”. Now we can test the navigation.


First we get the root node’s content via url: /sap/opu/odata/sap/ZFLIGHT_COM_CDS/Zflight_Com(connid=’0400′,carrid=’LH’) .


And in the response, we are told that the correct url for navigation from current node to its child node is just to append the navigation property defined in metadata, toItem, to the end of url, that is, /sap/opu/odata/sap/ZFLIGHT_COM_CDS/Zflight_Com(connid=’0400′,carrid=’LH’)/to_Item .


How the navigation is implemented in ABAP side

Set the breakpoint in the method below and re-trigger the navigation operation.

Check the generated SQL statement in variable statement in line 27.


SELECT "Zsflight_Child"."CARRID" AS "CARRID", "Zsflight_Child"."CONNID" AS "CONNID", "Zsflight_Child"."FLDATE" AS "FLDATE" FROM "ZSFLIGHTCHILD" AS "Zsflight_Child"
WHERE "Zsflight_Child"."CARRID" = ? AND "Zsflight_Child"."CONNID" = ? AND "Zsflight_Child"."MANDT" = '001' WITH PARAMETERS( 'LOCALE' = 'CASE_INSENSITIVE' )

The value for two placeholders ( ? ) are stored in me->parameters->param_tab:


And check response in et_flag_data:



Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member


      This blog helps me a lot on CDS navigation development.

      However, when I association the root-child views with cardinality [0..*], one ATC error raised.

      " Key of target view fully defined in on-condition but maximum target cardinality of association not equal 1".

      Do you have any idea solving this error?


      Thanks and regards,


      Author's profile photo Sebastian Freilinger-Huber
      Sebastian Freilinger-Huber

      Hi Avery,

      is it possible that you didn't define sflight.fldate as key field in your child view?

      Best regards,


      Author's profile photo Timothy Hughes
      Timothy Hughes


      Thanks for your super informative blogs..Very impressive.

      Question for you...If you add the annotation @DefaultAggregation: #SUM to the root view (pretending you had a numeric field there), It is my experience that the KEY of the root CDS view will change to a Generated_ID, not the key you specify.  Due to this new key, the navigation via Associations does not work.

      Have you experienced this?  Do you have any idea how to handle that (short of using SEGW)?



      p.s. I have an app that I really need to have totals, and navigate to the details (old fashioned ALV + Hotspot replication).


      Author's profile photo Vikash Rakshit
      Vikash Rakshit

      Hi Jerry ,

      I followed the above steps for the navigation but while activating i am getting error. can you please let me know how you activated cds1 and cds 2 as they are using Zsflight_Child and zspfli_root respectively .but this are new cds and using one another so while activating i am getting error as  Zsflight_Child and zspfli_root are not active in the dictionary.

      Author's profile photo Tobias Vogel
      Tobias Vogel

      Try creating them without the association part first. As soon as you created and activated them, add the associations.

      That worked for me

      Regards, Tobias

      Author's profile photo kyo choi
      kyo choi

      You have to activate them together.

      Author's profile photo Arun Muthukumarasamy
      Arun Muthukumarasamy

      Hi Guys,

      I have a doubt... why do we need the 3rd view for exposing the data to Odata? why can't we expose the Root view itself to OData?

      Regards, Arun

      Author's profile photo Vikash Rakshit
      Vikash Rakshit

      we always use to expose the consumption view . For navigation we require two entity sets which cannot be handled via root views. so we created a third view to expose as odata service which can handle navigation.




      Author's profile photo Ebrahim Hatem
      Ebrahim Hatem

      Thank you very much Jerry for this nice blog.

      it is really interesting, but how can I debug the CDS view? .. When you have entity   header/to_item . , in ABAP , we can debug our select statement but could we do it in CDS?




      Author's profile photo kyo choi
      kyo choi

      CDS views are like it says just the views so you cannot debug.  However OData implementations are ABAP so any OData created from CDS views you can debug and view the entities.

      Author's profile photo Desislava Ivanovich
      Desislava Ivanovich

      Nice example and nice blog. But nevertheless I still do not understand why we need the OData service(in this case created via annotation) to be created from CONSUMPTION CDS view. If I repeat exactly the steps in the metadata we have 2 entities which are with one and the same content , the root entity and the consumption entity. The root entity even does not have a navigation to the child one.

      Therefore I would not use the consumption but would have the Root CDS view to hold the OData publish annotation to true. Thus we will not have duplicate data in the metadata.

      What about that? ?

      Author's profile photo kyo choi
      kyo choi

      Navigation features are used in UI5/Fiori Application which consumes the OData.  Therefore you need to create the OData.  The navigation feature that he's explaining is also using the XML output of the OData.  Please check the section that below,

      OData metadata request via url /sap/opu/odata/sap/ZFLIGHT_COM_CDS/$metadata in gateway client.

      However for Restful ABAP, these are all automazically done.  Please check out the RAP which also explains about the consumption views.

      Author's profile photo Sandeep Kumar Yadav
      Sandeep Kumar Yadav

      Thank you very much Jerry for this nice blog.

      I have one question for the same topic navigation, Let’s say I have three level hierarchy


      ——-B(Child Of A)

      ————–C(Child of B)


      How we can define navigation for the same. I tried but not successful, If you have any example for the above case, Kindly share.



      Author's profile photo Roopashree V
      Roopashree V

      Hi Sandeep,


      You can achieve this by defining the below annotations

      Annotation for C

      @ObjectModel.association.type: [#TO_COMPOSITION_PARENT] B


      Annotation for B

      @ObjectModel.association.type: [#TO_COMPOSITION_CHILD] C

      @ObjectModel.association.type: [#TO_COMPOSITION_PARENT,#TO_COMPOSITION_ROOT]   A