CDS Annotations Part 2: Semantic Annotations for Currency, Units and Texts
Make data self-describing with semantic annotations: amounts with currencies, quantities with units, text elements and text associations, languages, and admin fields that RAP maintains automatically.
Explanation
📌 KEY POINTS
✅ Every amount needs @Semantics.amount.currencyCode; every quantity needs @Semantics.quantity.unitOfMeasure.
✅ Show texts next to codes with @ObjectModel.text.element or a text association.
✅ Admin fields (@Semantics.user.* / @Semantics.systemDateTime.*) are filled automatically in managed RAP.
⚠️ Without semantics, Fiori shows raw numbers and analytics may sum different currencies.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 1 introduced the families. Semantic annotations come first because they describe what the data means — every consumer benefits from them.
━━━━━━━━━━━━━━━━━━━━
▶ 1. AMOUNTS AND CURRENCIES
@Semantics.amount.currencyCode: 'CurrencyCode'
net_amount as NetAmount,
currency_code as CurrencyCode,
Effects: Fiori formats the amount with the right decimals (JPY has none, others two or three), shows the currency, and analytics aggregates per currency. The currency element must be in the same view.
In CDS view entities, the currency-code field itself needs no separate annotation; the reference from the amount is enough.
━━━━━━━━━━━━━━━━━━━━
▶ 2. QUANTITIES AND UNITS
@Semantics.quantity.unitOfMeasure: 'OrderUnit'
order_qty as OrderQuantity,
order_unit as OrderUnit,
Same idea: correct display, conversion and aggregation per unit.
━━━━━━━━━━━━━━━━━━━━
▶ 3. TEXTS FOR CODES
Users want "Completed", not "C". Two ways:
- Text element in the same view: @ObjectModel.text.element: ['StatusText'] on the code field, with StatusText calculated or read in the view.
- Text association: @ObjectModel.text.association: '_StatusText' on the code, pointing to a text view annotated with @ObjectModel.dataCategory: #TEXT, where the language field has @Semantics.language: true and the description @Semantics.text: true.
Fiori then shows "Completed (C)" or only the text, controlled by @UI.textArrangement.
💡 TIP: text associations automatically use the logon language — no hard-coded language filter needed in the consumer.
━━━━━━━━━━━━━━━━━━━━
▶ 4. ADMIN FIELDS FOR RAP
@Semantics.user.createdBy: true, @Semantics.systemDateTime.createdAt: true, @Semantics.user.localInstanceLastChangedBy: true, @Semantics.systemDateTime.localInstanceLastChangedAt: true, @Semantics.systemDateTime.lastChangedAt: true.
In managed RAP these fields are filled automatically on create and update; localInstanceLastChangedAt is the typical etag master and lastChangedAt the total etag (Managed RAP Part 2).
⚠️ WATCH OUT: if the annotation is missing, the field stays empty and ETag checks do not work.
━━━━━━━━━━━━━━━━━━━━
▶ 5. OTHER USEFUL SEMANTICS
- @Semantics.language: true — marks a language field.
- @Semantics.businessDate.from / to — validity periods.
- @Semantics.email.address, @Semantics.telephone.type — contact data.
- @ObjectModel.representativeKey — the key element that represents the entity (e.g. in text and value-help views).
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Annotate amounts and quantities in ZI_SalesOrderItem.
- Create the text view ZI_OrderStatusText (code example) and a text association in ZI_SalesOrder.
- Annotate admin fields in ZR_PurchReq.
- Preview in Fiori: amounts formatted, status shown as text.
✅ CHECKPOINT: your data explains itself to every consumer.
Code example
// ===== Step 1: amounts and quantities =====define view entity ZI_SalesOrderItem as select from zso_item{ key sales_order as SalesOrder, key sales_order_item as SalesOrderItem, @Semantics.quantity.unitOfMeasure: 'OrderUnit' order_qty as OrderQuantity, order_unit as OrderUnit, @Semantics.amount.currencyCode: 'CurrencyCode' net_amount as NetAmount, currency_code as CurrencyCode} // ===== Step 2a: text view (one row per status and language) =====@ObjectModel.dataCategory: #TEXT@ObjectModel.representativeKey: 'Status'@EndUserText.label: 'Order Status Text'define view entity ZI_OrderStatusText as select from zso_status_t{ key status as Status, @Semantics.language: true key spras as Language, @Semantics.text: true status_text as StatusText} // ===== Step 2b: text association on the code field =====define view entity ZI_SalesOrder as select from zso_head association [0..*] to ZI_OrderStatusText as _StatusText on $projection.OverallStatus = _StatusText.Status{ key sales_order as SalesOrder, @ObjectModel.text.association: '_StatusText' // Fiori shows the text overall_status as OverallStatus, _StatusText} // ===== Step 3: RAP admin fields (base BO view) =====// @Semantics.user.createdBy: true created_by as CreatedBy,// @Semantics.systemDateTime.createdAt: true created_at as CreatedAt,// @Semantics.user.localInstanceLastChangedBy: true last_changed_by as LastChangedBy,// @Semantics.systemDateTime.localInstanceLastChangedAt: true// local_last_changed_at as LocalLastChangedAt,// @Semantics.systemDateTime.lastChangedAt: true last_changed_at as LastChangedAtReal project scenario
An order-value dashboard summed NetAmount across all orders and showed one total. Orders were in EUR, USD and JPY, so the total was meaningless — and nobody noticed for weeks because the number looked plausible.
Adding @Semantics.amount.currencyCode to the interface view made the analytics layer aggregate per currency automatically, and the dashboard showed three totals. In the same review, status codes were given a text association, and Fiori lists started showing "Completed" instead of "C" without any UI code.
Common mistakes
- Amounts without a currency reference, quantities without a unit reference.
- Referencing a currency field that is not in the same view.
- Hard-coding the language in text joins instead of using text associations.
- Missing admin field annotations, so managed RAP does not fill them and ETags fail.
- Mixing text and code in one calculated field instead of using text semantics.
Best practices
- Annotate every amount and quantity at the interface layer.
- Model texts as text views with dataCategory #TEXT and text associations.
- Annotate admin fields in every RAP base view.
- Use @UI.textArrangement to control how text and code are shown.
- Check the result in Fiori preview and $metadata.
Interview angle
Questions: "How do you connect an amount to its currency in CDS?", "How do you show texts for codes?", "Which annotations does managed RAP need for admin fields?"
Strong answer: @Semantics.amount.currencyCode and @Semantics.quantity.unitOfMeasure with the reference field in the same view; texts via @ObjectModel.text.element or text associations to a #TEXT view with @Semantics.language and @Semantics.text; admin fields via @Semantics.user.* and @Semantics.systemDateTime.*, with localInstanceLastChangedAt as ETag. Mention per-currency aggregation as a business reason.
Practice this lesson
Quick check
1. An order-value dashboard sums NetAmount across EUR, USD and JPY into one total. Which fix addresses the root cause?
2. A CDS view exposes an amount field together with a separate currency key field. Which annotation must be added to the amount field so that Fiori Elements and OData correctly format and display it as a currency amount?
3. A CDS view has a status code field along with an associated status description text field. Which annotation setting controls whether the UI displays the code, the text, both, or the text followed by the code in parentheses?
Interview questions
1. How do you connect amounts, quantities and texts to their semantics in CDS, and what goes wrong without it?
Answer it in your own words first, then compare.
2. Where should each kind of annotation live in a RAP stack (R_, C_, metadata extension), and why?
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 Annotations Part 1: What Annotations Are and Where They Apply
- CDS Annotations Part 3: Fiori UI Annotations — Line Items, Facets and Selection Fields
- CDS Annotations Part 4: Metadata Extensions — Separating UI from the Data Model
- CDS Annotations Part 5: Troubleshooting Precedence, Metadata and UI Behavior