CDS Associations Part 1: Source, Target, ON Condition and Cardinality
Declare CDS associations correctly: source and target, the ON condition, $projection, cardinality, and exposing the association so consumers can use it.
What this complete series covers
Learn CDS Associations in a clear, practical sequence — from the basic idea to real project use, troubleshooting, and interview-ready understanding.
- Who it is for
- Best for SAP consultants, developers, and learners who want a practical understanding of CDS Associations.
- Prerequisites
- Basic ABAP and ADT in Eclipse are recommended. The series explains the RAP/CDS/OData concepts as they are introduced.
- Final outcome
- By the end, you should be able to explain CDS Associations clearly, follow the main end-to-end flow, apply it in a project scenario, and troubleshoot the most common issues.
- Part 1: CDS Associations Part 1: Source, Target, ON Condition and Cardinality
Build CDS associations correctly by understanding source and target entities, ON-condition semantics, exposure, cardinality, and how the association becomes executable SQL only whe
- Part 2: CDS Associations Part 2: Path Expressions and How Associations Become Joins
Understand how CDS path expressions traverse associations, when a join is instantiated, how filters become part of the generated SQL, and why path usage can change result cardinality.
- Part 3: CDS Associations Part 3: To-One vs To-Many — Semantics and Performance
Choose CDS association cardinality from business truth, understand the consequences of to-one and to-many relationships, and diagnose cardinality-driven correctness and performance issues.
- Part 4: CDS Associations Part 4: Associations vs Compositions in a RAP Business Object
Distinguish generic CDS associations from RAP composition relationships, understand root-child ownership, and model transactional business objects without confusing navigation with
- Part 5: CDS Associations Part 5: Troubleshooting Duplicates, Missing Data and Slow Queries
Use a systematic production method to diagnose CDS association defects by proving data grain, ON-condition uniqueness, path filters, generated SQL, and consumer behavior before changing the model.
System and release assumptions: Examples target recent SAP S/4HANA / ABAP Cloud capabilities. RAP, CDS, OData, and Fiori Elements syntax and tooling can differ by ABAP platform release.
Explanation
📌 KEY POINTS
✅ An association is a declared relationship — it is joined only when someone uses it.
✅ Syntax: association [cardinality] to Target as _Alias on <condition>.
✅ Use $projection (or the source alias) in the ON condition and expose the field used in it.
⚠️ Cardinality must describe the real data — wrong cardinality causes wrong results and slow plans.
━━━━━━━━━━━━━━━━━━━━
▶ WHAT THIS SERIES COVERS
- Part 1 — declaring an association (this lesson)
- Part 2 — path expressions: how associations become joins
- Part 3 — to-one vs to-many: semantics and performance
- Part 4 — associations vs compositions in RAP
- Part 5 — troubleshooting duplicates, missing data and slow queries
Prerequisite: CDS Views Parts 1–3.
━━━━━━━━━━━━━━━━━━━━
▶ WHAT AN ASSOCIATION IS
A join says "combine these two sources now". An association says "these two entities are related like this" and leaves it to the consumer whether to follow the relationship. That makes one view reusable: a list that needs only order numbers never pays for the customer join, while an object page can follow _Customer to show the name.
━━━━━━━━━━━━━━━━━━━━
▶ THE SYNTAX, PIECE BY PIECE
association [0..1] to ZI_Customer as _Customer
on $projection.Customer = _Customer.Customer
- [0..1] — cardinality: how many target rows per source row (Part 3).
- to ZI_Customer — the target: another CDS entity (not a table in clean designs).
- as _Customer — the alias. Convention: start with an underscore.
- on … — the join condition. The source side uses $projection.<element> (the element name in your view) or the source alias; the target side uses _Alias.<element>.
📌 REMEMBER: every source field used in the ON condition with $projection must be in the element list.
━━━━━━━━━━━━━━━━━━━━
▶ EXPOSING THE ASSOCIATION
Declaring the association is not enough for consumers. Add the alias to the element list:
{ …, Customer, _Customer }
Now other views, ABAP SQL and OData can follow it. If you only need it inside this view (e.g. to read one field), you may use it in a path without exposing it.
━━━━━━━━━━━━━━━━━━━━
▶ CARDINALITY NOTATION
- [0..1] or [1] — to-one (at most one / exactly one target row).
- [0..*] or [*] — to-many.
- [1..*] — at least one.
If you omit it, the default is [0..1] — never rely on the default; always write it.
💡 TIP: newer releases also offer a more readable cardinality syntax (e.g. "association of many to one"). Use it if your system supports it; the meaning is the same.
━━━━━━━━━━━━━━━━━━━━
▶ ASSOCIATIONS WITH EXTRA CONDITIONS
The ON condition can contain more than key equality, e.g. a language condition:
association [0..1] to ZI_OrderStatusText as _StatusText
on $projection.OverallStatus = _StatusText.Status
and _StatusText.Language = $session.system_language
Such a condition turns a to-many text table into a to-one association.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Open ZI_SalesOrder (from CDS Views).
- Add associations to the customer, the items and the status text as in the code example.
- Expose them in the element list; activate.
- Open Data Preview, select a row, and use "Follow Association" to navigate — no join was written.
✅ CHECKPOINT: you can declare, expose and navigate an association. Part 2 shows exactly what SQL is generated when you use it.
Code example
// ===== Step 1: associations in the interface view =====@AccessControl.authorizationCheck: #CHECK@EndUserText.label: 'Sales Order'define view entity ZI_SalesOrder as select from zso_head // to-one: each order has at most one customer association [0..1] to ZI_Customer as _Customer on $projection.Customer = _Customer.Customer // to-many: an order has many items association [0..*] to ZI_SalesOrderItem as _Item on $projection.SalesOrder = _Item.SalesOrder // to-one thanks to the language condition association [0..1] to ZI_OrderStatusText as _StatusText on $projection.OverallStatus = _StatusText.Status and _StatusText.Language = $session.system_language{ key sales_order as SalesOrder, customer_id as Customer, // used in ON -> must be in the element list overall_status as OverallStatus, // used in ON -> must be in the element list order_date as OrderDate, currency_code as CurrencyCode, // Step 2: expose the associations for consumers _Customer, _Item, _StatusText} // ===== Step 3: consumers decide what to follow =====// ABAP SQL - join to customer ONLY because it is used here:// SELECT SalesOrder, \_Customer-CustomerName AS CustomerName// FROM zi_salesorder INTO TABLE @DATA(orders).//// OData - navigation only when requested:// GET .../SalesOrder('4711')?$expand=_ItemReal project scenario
A project had one "universal" sales order view with inner joins to customer, material, plant and status texts. Every consumer — list report, API and three analytics queries — paid for all joins, and orders with a missing plant disappeared entirely because of the inner join.
The team rebuilt it as an interface view with associations and only the header fields. Each consumer now follows only the associations it needs. The list report became several times faster, and the "missing orders" defect vanished because unused associations are no longer joined at all.
Common mistakes
- Using hard joins where an association would let consumers decide.
- Using a field with $projection in the ON condition without adding it to the element list.
- Forgetting to expose the association, so consumers cannot navigate.
- Omitting cardinality and relying on the default.
- Declaring a text association without a language condition, making it to-many.
- Pointing associations at tables instead of CDS entities.
Best practices
- Model relationships as associations in interface views.
- Always state cardinality explicitly and correctly.
- Name associations with a leading underscore and a business name.
- Add language or validity conditions to make text and time-dependent relations to-one.
- Expose associations that consumers need; keep internal ones unexposed.
Interview angle
Questions: "What is a CDS association?", "How is it different from a join?", "What is $projection?", "Why must you specify cardinality?"
Strong answer: an association is a declared relationship that becomes a join only when used (path expression or $expand). $projection refers to elements of the current view in the ON condition, and those elements must be in the element list. Cardinality documents the business relation and influences correctness and optimization; the default [0..1] should never be relied on. Mention text associations with a language condition as a practical example.
Practice this lesson
Quick check
1. In an association ON condition, a source field is referenced with $projection. What must be true?
2. In ABAP CDS, which association declaration restricts the target instance count to at most one, but does not require that a target instance exists?
3. What is a key conceptual difference between a CDS association and a classic explicit JOIN defined in the FROM clause?
Interview questions
1. What design rules do you follow for associations in an interface view layer?
Answer it in your own words first, then compare.
2. What is a CDS association, how is it declared, and how does it differ from a join?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- CDS Associations Part 2: Path Expressions and How Associations Become Joins
- CDS Associations Part 3: To-One vs To-Many — Semantics and Performance
- CDS Associations Part 4: Associations vs Compositions in a RAP Business Object
- CDS Associations Part 5: Troubleshooting Duplicates, Missing Data and Slow Queries