CDS Views Part 7: Annotations for Semantics, Texts, Search and UI
Use CDS annotations to give data meaning: currency and unit semantics, text views and text associations, language-dependent descriptions, search annotations, UI annotations for Fiori elements, and metadata extensions that keep UI layout out of the data model.
Explanation
📌 KEY POINTS
✅ Annotations (@…) add metadata to a view or field; the database ignores most of them, but frameworks (OData, Fiori elements, analytics, search) read them.
✅ Semantic annotations (currency, unit, text, language) describe what a field is; UI annotations describe how an app shows it.
✅ Metadata extensions (annotate entity … with) move UI annotations into a separate object, so the data model stays clean and layouts can be changed per layer.
⚠️ Annotations have scopes — view level, element level, parameter level. A misspelled or wrongly placed annotation often gives only a warning, and the app silently ignores it.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 5 introduced consumption views. Now we make them meaningful for Fiori, search and value helps.
━━━━━━━━━━━━━━━━━━━━
▶ 1. ANNOTATION BASICS
- Syntax: @Namespace.annotation: value, placed before the view or before a field.
- Common namespaces: EndUserText, Semantics, ObjectModel, Search, UI, Consumption, Analytics, AccessControl, VDM.
- ADT code completion (Ctrl+Space) shows valid annotations and their scope.
━━━━━━━━━━━━━━━━━━━━
▶ 2. SEMANTIC ANNOTATIONS
- @Semantics.amount.currencyCode: 'CurrencyField' — amount with its currency.
- @Semantics.quantity.unitOfMeasure: 'UnitField' — quantity with its unit.
- @Semantics.language: true / @Semantics.text: true — in text views.
- @EndUserText.label / quickInfo — field labels shown in apps.
━━━━━━━━━━━━━━━━━━━━
▶ 3. TEXT VIEWS AND TEXTS
- Text view: @ObjectModel.dataCategory: #TEXT, keys = code + language, one text field.
- In the main view: association to the text view and @ObjectModel.text.element pointing to the description field, or @ObjectModel.text.association.
- Filtered path with $session.system_language shows the text in the user's language.
━━━━━━━━━━━━━━━━━━━━
▶ 4. SEARCH
- @Search.searchable: true at view level enables free-text search (OData $search, Fiori search field).
- @Search.defaultSearchElement: true on the fields to search; @Search.fuzzinessThreshold for fuzzy matching.
━━━━━━━━━━━━━━━━━━━━
▶ 5. UI ANNOTATIONS (FIORI ELEMENTS)
- @UI.headerInfo: object name singular/plural and title.
- @UI.lineItem: columns of the list report with position.
- @UI.selectionField: filter bar fields.
- @UI.identification / @UI.facet: object page layout.
- @Consumption.valueHelpDefinition: value help from another view.
━━━━━━━━━━━━━━━━━━━━
▶ 6. METADATA EXTENSIONS
- View needs @Metadata.allowExtensions: true.
- Separate DDLX object: annotate entity ZC_X with { … } holding UI annotations.
- @Metadata.layer: #CORE, #LOCALIZATION, #INDUSTRY, #PARTNER, #CUSTOMER — higher layers override lower ones.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Create text view ZI_SalesOrderTypeText over TVAKT.
- Create consumption view ZC_SalesOrderList with a text association and filtered path for the order type name.
- Add search annotations; allow metadata extensions.
- Create a metadata extension with lineItem and selectionField annotations.
- Preview in ADT; later expose via OData (next topic) and see the Fiori list generated from annotations.
✅ CHECKPOINT: you can separate meaning (semantic annotations) from layout (UI annotations in metadata extensions).
Code example
// ===== STEP 1: text view =====@AccessControl.authorizationCheck: #NOT_REQUIRED@EndUserText.label: 'Sales order type text'@ObjectModel.dataCategory: #TEXTdefine view entity ZI_SalesOrderTypeText as select from tvakt{ key auart as SalesOrderType, @Semantics.language: true key spras as Language, @Semantics.text: true bezei as SalesOrderTypeName} // ===== STEP 2: consumption view with texts and search =====@AccessControl.authorizationCheck: #NOT_REQUIRED@EndUserText.label: 'Sales order list'@Metadata.allowExtensions: true@Search.searchable: true@UI.headerInfo: { typeName: 'Sales Order', typeNamePlural: 'Sales Orders' }define view entity ZC_SalesOrderList as select from ZI_SalesOrderHeader association [0..*] to ZI_SalesOrderTypeText as _TypeText on $projection.SalesOrderType = _TypeText.SalesOrderType{ @Search.defaultSearchElement: true key SalesOrder, CreationDate, @ObjectModel.text.element: ['SalesOrderTypeName'] SalesOrderType, _TypeText[1: Language = $session.system_language].SalesOrderTypeName as SalesOrderTypeName, @Search.defaultSearchElement: true SoldToParty, @Semantics.amount.currencyCode: 'TransactionCurrency' NetAmount, TransactionCurrency, _TypeText} // ===== STEP 3: metadata extension (separate DDLX object) =====@Metadata.layer: #CUSTOMERannotate entity ZC_SalesOrderList with{ @UI.lineItem: [{ position: 10 }] @UI.selectionField: [{ position: 10 }] SalesOrder; @UI.lineItem: [{ position: 20 }] CreationDate; @UI.lineItem: [{ position: 30 }] SalesOrderType; @UI.lineItem: [{ position: 40 }] @UI.selectionField: [{ position: 20 }] SoldToParty; @UI.lineItem: [{ position: 50 }] NetAmount;} * ===== STEP 4: classic report - texts already resolved =====REPORT zcds_so_list_texts. TYPES: BEGIN OF ty_row, salesorder TYPE vbeln_va, salesordertype TYPE auart, salesordertypename TYPE bezei20, END OF ty_row. DATA: lt_row TYPE STANDARD TABLE OF ty_row, ls_row TYPE ty_row. START-OF-SELECTION. SELECT salesorder salesordertype salesordertypename FROM zc_salesorderlist INTO TABLE lt_row UP TO 100 ROWS. LOOP AT lt_row INTO ls_row. WRITE: / ls_row-salesorder, ls_row-salesordertype, ls_row-salesordertypename. ENDLOOP.Real project scenario
A Fiori list report built on a custom CDS view showed order types only as codes (TA, ZOR) and labels like "AUART". Users kept a printed code list next to the screen.
The developer added a text view over TVAKT, a text association with @ObjectModel.text.element, and @EndUserText labels. UI annotations were moved to a metadata extension so the functional team could reorder columns without touching the data model. The app then showed "Standard Order (TA)" in the logon language.
Common mistakes
- Putting UI layout annotations directly into basic or composite views.
- Text path without language filter, returning one row per language.
- Forgetting @Metadata.allowExtensions, so the DDLX has no effect.
- Misspelled annotations accepted with a warning and silently ignored.
- Using @Search.searchable without marking any defaultSearchElement.
Best practices
- Semantics in the model, UI in metadata extensions.
- Use text views with @ObjectModel.dataCategory: #TEXT and language filters.
- Check annotation scope with ADT code completion.
- Treat activation warnings on annotations as errors.
- Reuse SAP value help views (I_*VH) where available.
Interview angle
Questions: "What are CDS annotations used for?", "What is a metadata extension?", "How do you show language-dependent texts?"
Strong answer: annotations provide metadata read by frameworks — semantics (currency, unit, text), search, UI for Fiori elements, analytics, access control. Metadata extensions (annotate entity) hold UI annotations separately with layers (#CORE to #CUSTOMER), requiring @Metadata.allowExtensions. Texts via a #TEXT view with language key, a text association and @ObjectModel.text.element, filtered by $session.system_language.
Practice this lesson
Quick check
1. A metadata extension with UI annotations for ZC_SalesOrderList has no effect in the app. What is the most likely cause?
2. Which annotation links an amount field to its currency field in a CDS view entity?
3. Order types appear only as codes in a CDS-based list. Which modelling shows the description in the user's language?
Interview questions
1. How do you expose a CDS view as OData?
Answer it in your own words first, then compare.
2. A Fiori list report generated from CDS annotations shows amounts without currency and order types only as codes with technical labels. What would you change in the CDS model?
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 Views Part 1: What CDS Is and Your First View Entity
- CDS Views Part 10: Performance and Troubleshooting
- CDS Views Part 2: Joins, Expressions, CASE, CAST and Functions
- CDS Views Part 3: Aggregation and Analytical Annotations
- CDS Views Part 4: CDS View Entity vs Classic (DDIC-Based) CDS View
- CDS Views Part 5: VDM Layering — Basic, Composite and Consumption Views
- CDS Views Part 6: Associations and Cardinality
- CDS Views Part 8: DCL Access Control