Skip to content

Lesson 5 Companion — CDS Associations & Path Expressions ​

This companion expands Lesson 5 — CDS Associations & Path Expressions.

It includes:

  • precise association terminology;
  • cardinality guidance;
  • $projection explanation;
  • path-expression behavior;
  • exposed-association behavior;
  • Data Preview navigation;
  • complete Route reference code;
  • complete Booking practice reference code;
  • a to-many challenge reference;
  • troubleshooting;
  • current SAP documentation links.

How to use this companion

Use it after attempting the main lesson and practice, or whenever you want to compare your model with a complete reference implementation.

Related Lesson 5 files:

  1. Lesson 5 — CDS Associations & Path Expressions
  2. Lesson 5 Practice — Booking Associations

1. Why associations follow joins ​

Current SAP CDS supports both:

text
join expressions
associations

Associations are reusable relationship definitions. When a path target field is used, CDS can instantiate the relationship as a database join.

This makes the course sequence intentional:

text
Lesson 4
explicit joins
  ↓
understand ON, join type, and row multiplication

Lesson 5
associations
  ↓
name and reuse those relationships

Associations are easier to reason about once learners already understand the relational mechanics underneath.


2. Associations are directional ​

A normal association is defined in its source entity and points to a target.

Example:

text
Connection ──► Carrier

does not automatically create:

text
Carrier ──► Connection

If reverse navigation is required, another relationship must be modeled from the reverse source.

This prepares students for later RAP relationships where both directions can be modeled explicitly.


3. Why this lesson targets CDS entities ​

The guided lesson associates to:

text
/DMO/I_Carrier
/DMO/I_Airport

rather than directly to:

text
/DMO/CARRIER
/DMO/AIRPORT

The intention is to reinforce:

text
consumer model
  ↓
reusable CDS model
  ↓
persistence

This is closer to current SAP RAP examples, where reference/master data is typically consumed through CDS entities.


4. Verified target fields ​

Current SAP Flight Reference Scenario documentation defines:

/DMO/I_Carrier ​

text
AirlineID    key
Name
CurrencyCode

/DMO/I_Airport ​

text
AirportID    key
Name
City
CountryCode

/DMO/I_Customer ​

text
CustomerID   key
FirstName
LastName
City
CountryCode
...

/DMO/I_Connection ​

text
AirlineID      key
ConnectionID   key
DepartureAirport
DestinationAirport
DepartureTime
ArrivalTime
Distance
DistanceUnit

These names are the target-side element names used in the lesson and practice.


5. Numeric cardinality in this course ​

The lesson uses numeric cardinality notation:

text
[0..1]
[1..1]
[0..*]
[1..*]

Current SAP RAP documentation continues to use these forms extensively.

Current ABAP releases also support newer source/target cardinality syntax, for example forms such as:

text
association of exact one to many ...

The numeric notation remains clear and compatible for the course's current level.


6. Cardinality is a model contract ​

Cardinality should reflect the real relationship.

Examples:

text
Booking → Customer
to one

Connection → Carrier
to one

Carrier → Connections
to many

Do not choose cardinality based on what is easiest to type.

Ask:

text
Can no target exist?
Can several targets exist?
Does the ON condition identify the complete target key?

7. To-one relationships and complete target keys ​

SAP guidance emphasizes that a real to-one relationship should normally map the complete target key.

Example target:

text
/DMO/I_Connection

key AirlineID
key ConnectionID

A Booking association must therefore use:

abap
on  $projection.CarrierId    = _Connection.AirlineID
and $projection.ConnectionId = _Connection.ConnectionID

Using only:

text
ConnectionID

does not identify the full target record.

This is the Lesson 4 complete-key rule expressed in association form.


8. $projection ​

Suppose the source field is:

abap
Booking.customer_id as CustomerId

An association can refer to the current CDS element:

abap
$projection.CustomerId

For example:

abap
association [1..1] to /DMO/I_Customer as _Customer
  on $projection.CustomerId = _Customer.CustomerID

This lets the association use the current model's field name rather than the persistence source name.


9. Source fields needed by exposed associations ​

If an association is exposed publicly, the source fields used in its ON condition must remain available in the exposing entity.

For example:

text
_Carrier

depends on:

text
CarrierId

Therefore CarrierId needs to remain part of the current entity's element list.


10. Path target fields ​

This:

abap
_Carrier.Name as CarrierName

means:

text
navigate _Carrier
read Name from the target
expose it as CarrierName

CarrierName is then an ordinary scalar element for consumers.

The relationship logic remains in CDS.


11. Default join semantics of a CDS path target field ​

Current SAP documentation states that when a path target field is used in the element list of a CDS entity, a left outer join is generated by default.

Therefore:

abap
_Carrier.Name

has default left-outer semantics even if Lesson 4 explicitly used:

abap
inner join

This distinction is useful.


12. Cardinality vs join type ​

These concepts are related but not identical.

text
cardinality
=
what relationship is expected

join type
=
how rows are combined for a particular path use

So:

text
[1..1]

does not mean:

text
the path must be an INNER JOIN

The default path-target access is still left outer.


13. Path join attributes ​

Current CDS path syntax can override the default join type.

Example:

abap
_Carrier[inner].Name

This explicitly requests inner-join behavior for that path usage.

The main lesson does not use it because the goal is to teach association modeling first.


14. Exposing an association ​

Compare:

abap
_Carrier.Name as CarrierName

with:

abap
_Carrier

The first exposes:

text
a scalar value

The second exposes:

text
the navigation relationship

This distinction matters for:

text
CDS consumers
projection layers
service navigation
RAP models

15. Data Preview navigation ​

Current ADT provides Follow Association in CDS Data Preview.

The intended workflow is:

text
open Data Preview
  ↓
Follow Association
  ↓
choose _Carrier / _OriginAirport / ...
  ↓
inspect target result
  ↓
navigate back with breadcrumb

This is one of the strongest practical demonstrations of why an exposed association is different from a copied scalar field.


16. Complete Route association reference ​

abap
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Route with Associations'

define view entity ZI_Route_Assoc_###
  as select from /dmo/connection as Connection

    association [1..1] to /DMO/I_Carrier as _Carrier
      on $projection.CarrierId = _Carrier.AirlineID

    association [1..1] to /DMO/I_Airport as _OriginAirport
      on $projection.OriginAirportId = _OriginAirport.AirportID

    association [1..1] to /DMO/I_Airport as _DestinationAirport
      on $projection.DestinationAirportId = _DestinationAirport.AirportID

{
  key Connection.carrier_id       as CarrierId,
  key Connection.connection_id    as ConnectionId,

      _Carrier.Name               as CarrierName,

      Connection.airport_from_id  as OriginAirportId,
      _OriginAirport.Name         as OriginAirportName,
      _OriginAirport.City         as OriginCity,
      _OriginAirport.CountryCode  as OriginCountryCode,

      Connection.airport_to_id    as DestinationAirportId,
      _DestinationAirport.Name        as DestinationAirportName,
      _DestinationAirport.City        as DestinationCity,
      _DestinationAirport.CountryCode as DestinationCountryCode,

      Connection.departure_time   as DepartureTime,
      Connection.arrival_time     as ArrivalTime,
      Connection.distance         as Distance,
      Connection.distance_unit    as DistanceUnit,

      _Carrier,
      _OriginAirport,
      _DestinationAirport
}

17. Why the source is still /DMO/CONNECTION ​

The lesson is focused on association mechanics.

Using:

text
/DMO/CONNECTION

as the main source keeps the new material concentrated on:

text
association declaration
cardinality
$projection
path expressions
exposure
navigation

A later course refactor could introduce a dedicated Connection interface entity first, but it is not required here.


18. Route Reader reference ​

abap
CLASS zcl_route_assoc_reader_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.

    TYPES tt_routes
      TYPE STANDARD TABLE OF zi_route_assoc_###
      WITH EMPTY KEY.

    METHODS get_all
      RETURNING VALUE(routes) TYPE tt_routes.

    METHODS get_from_country
      IMPORTING
        country_code TYPE /dmo/airport-country
      RETURNING
        VALUE(routes) TYPE tt_routes.

ENDCLASS.


CLASS zcl_route_assoc_reader_### IMPLEMENTATION.

  METHOD get_all.

    SELECT FROM zi_route_assoc_###
      FIELDS *
      ORDER BY CarrierId,
               ConnectionId
      INTO TABLE @routes.

  ENDMETHOD.


  METHOD get_from_country.

    SELECT FROM zi_route_assoc_###
      FIELDS *
      WHERE OriginCountryCode = @country_code
      ORDER BY CarrierId,
               ConnectionId
      INTO TABLE @routes.

  ENDMETHOD.

ENDCLASS.

19. Route Runner reference ​

abap
CLASS zcl_cds_l05_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

ENDCLASS.


CLASS zcl_cds_l05_### IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.

    DATA(reader) = NEW zcl_route_assoc_reader_###( ).

    DATA(routes) = reader->get_all( ).

    LOOP AT routes INTO DATA(route).

      out->write(
        |{ route-CarrierName }: | &&
        |{ route-OriginCity } -> { route-DestinationCity }|
      ).

    ENDLOOP.

  ENDMETHOD.

ENDCLASS.

20. Practice architecture ​

The practice uses:

text
/DMO/BOOKING
      ↓
ZI_BOOKING_ASSOC_###
      ├── _Customer ───► /DMO/I_Customer
      ├── _Carrier ────► /DMO/I_Carrier
      └── _Connection ─► /DMO/I_Connection

This is an excellent association exercise because _Connection requires a composite target key.


21. Practice association reference ​

abap
association [1..1] to /DMO/I_Customer as _Customer
  on $projection.CustomerId = _Customer.CustomerID

association [1..1] to /DMO/I_Carrier as _Carrier
  on $projection.CarrierId = _Carrier.AirlineID

association [1..1] to /DMO/I_Connection as _Connection
  on  $projection.CarrierId    = _Connection.AirlineID
  and $projection.ConnectionId = _Connection.ConnectionID

22. Practice complete CDS reference ​

abap
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Booking with Associations'

define view entity ZI_Booking_Assoc_###
  as select from /dmo/booking as Booking

    association [1..1] to /DMO/I_Customer as _Customer
      on $projection.CustomerId = _Customer.CustomerID

    association [1..1] to /DMO/I_Carrier as _Carrier
      on $projection.CarrierId = _Carrier.AirlineID

    association [1..1] to /DMO/I_Connection as _Connection
      on  $projection.CarrierId    = _Connection.AirlineID
      and $projection.ConnectionId = _Connection.ConnectionID

{
  key Booking.travel_id       as TravelId,
  key Booking.booking_id      as BookingId,

      Booking.booking_date    as BookingDate,

      Booking.customer_id     as CustomerId,
      _Customer.FirstName     as CustomerFirstName,
      _Customer.LastName      as CustomerLastName,

      Booking.carrier_id      as CarrierId,
      _Carrier.Name           as CarrierName,

      Booking.connection_id   as ConnectionId,
      _Connection.DepartureAirport   as DepartureAirportId,
      _Connection.DestinationAirport as DestinationAirportId,
      _Connection.DepartureTime      as DepartureTime,
      _Connection.ArrivalTime        as ArrivalTime,

      Booking.flight_date     as FlightDate,
      Booking.flight_price    as FlightPrice,
      Booking.currency_code   as CurrencyCode,

      _Customer,
      _Carrier,
      _Connection
}

23. Why the practice keeps first/last name separate ​

Lesson 4 already practiced:

text
CONCAT_WITH_SPACE

Lesson 5 should concentrate on association navigation.

The practice therefore exposes:

text
CustomerFirstName
CustomerLastName

through _Customer.

Students can optionally derive a display name, but it is not required to demonstrate the new concept.


24. Practice Reader reference ​

abap
CLASS zcl_booking_assoc_reader_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.

    TYPES tt_bookings
      TYPE STANDARD TABLE OF zi_booking_assoc_###
      WITH EMPTY KEY.

    METHODS get_all
      RETURNING VALUE(bookings) TYPE tt_bookings.

    METHODS get_by_carrier
      IMPORTING
        carrier_id TYPE /dmo/carrier-carrier_id
      RETURNING
        VALUE(bookings) TYPE tt_bookings.

ENDCLASS.


CLASS zcl_booking_assoc_reader_### IMPLEMENTATION.

  METHOD get_all.

    SELECT FROM zi_booking_assoc_###
      FIELDS *
      ORDER BY TravelId,
               BookingId
      INTO TABLE @bookings.

  ENDMETHOD.


  METHOD get_by_carrier.

    SELECT FROM zi_booking_assoc_###
      FIELDS *
      WHERE CarrierId = @carrier_id
      ORDER BY TravelId,
               BookingId
      INTO TABLE @bookings.

  ENDMETHOD.

ENDCLASS.

25. Practice Runner reference ​

abap
CLASS zcl_cds_l05_practice_### DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

ENDCLASS.


CLASS zcl_cds_l05_practice_### IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.

    DATA(reader) = NEW zcl_booking_assoc_reader_###( ).

    DATA(bookings) = reader->get_all( ).

    LOOP AT bookings INTO DATA(booking).

      out->write(
        |{ booking-TravelId }/{ booking-BookingId }: | &&
        |{ booking-CustomerFirstName } { booking-CustomerLastName } - | &&
        |{ booking-CarrierName }|
      ).

    ENDLOOP.

  ENDMETHOD.

ENDCLASS.

26. To-many challenge reference ​

One carrier can have many connections.

Reference:

abap
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Carrier Connections'

define view entity ZI_Carrier_Connections_###
  as select from /DMO/I_Carrier as Carrier

    association [0..*] to /DMO/I_Connection as _Connections
      on $projection.CarrierId = _Connections.AirlineID

{
  key Carrier.AirlineID as CarrierId,
      Carrier.Name      as CarrierName,

      _Connections
}

This is intentionally a navigation model.

Students should use Data Preview's Follow Association rather than flattening all Connection fields into the Carrier row.


27. Why [0..*] for the challenge ​

The reverse direction is:

text
Carrier → Connections

A carrier can have:

text
zero connections
one connection
many connections

Therefore:

text
[0..*]

is appropriate for the general relationship.

This contrasts cleanly with:

text
Booking → Carrier [1..1]

28. To-many row behavior ​

A to-many association can lead to more than one target row for one source.

If a model flattens a target field from a to-many path, row multiplication can occur.

That is the same relational effect students saw with joins in Lesson 4.

Associations do not remove the need to understand cardinality.


29. ABAP SQL path expressions ​

ABAP SQL can navigate exposed CDS associations as well.

Its syntax differs from CDS DDL path syntax; ABAP SQL path navigation in data-source positions uses backslash association notation.

The main lesson does not teach full ABAP SQL association-path syntax yet.

That is deliberate:

text
Lesson 5 goal
=
master CDS association modeling and navigation

not
=
master every possible consumer syntax

Students already have SQL Console and Reader access to the exposed scalar model.


30. Filtered path expressions ​

Current CDS supports path filters such as:

text
_Assoc[condition].Field

and attributes that can affect path cardinality and join behavior.

These are valuable for text models and restricted to-many relationships.

They are deferred until a real use case requires them rather than being added as syntax inventory.


31. Troubleshooting ​

Target object not found ​

Search with:

text
Ctrl + Shift + A

for:

text
/DMO/I_CARRIER
/DMO/I_AIRPORT
/DMO/I_CUSTOMER
/DMO/I_CONNECTION

Confirm the Flight Reference Scenario content is available in the training tenant.


AirlineID unknown ​

When target is:

text
/DMO/I_CARRIER

use its CDS key:

text
AirlineID

not the persistence field:

text
carrier_id

Country unknown on Airport ​

The target CDS field is:

text
CountryCode

Use:

abap
_OriginAirport.CountryCode

$projection.CarrierId unknown ​

Make sure the current entity exposes:

abap
... as CarrierId

with exactly the same spelling.


Follow Association does not list _Carrier ​

Make sure:

abap
_Carrier

itself is in the element list and the entity has been activated.

A scalar path field alone is not the same as exposed navigation.


_Connection practice relationship behaves incorrectly ​

Check the full target key:

text
AirlineID
ConnectionID

Both must participate in the ON condition.


32. Self-review checklist ​

A strong Lesson 5 implementation demonstrates:

  • target CDS entities understood before association coding;
  • meaningful association names;
  • correct cardinality;
  • complete target-key conditions;
  • deliberate use of $projection;
  • correct path target fields;
  • exposed associations;
  • successful Follow Association navigation;
  • correct distinction between scalar field and relationship;
  • no duplicated relationship logic in Reader/Runner;
  • readiness for semantic/text associations in Lesson 6.

33. Current SAP references ​