Service Definitions Part 6: Exposing Multiple Entities and Navigation
Expose several entities in one service correctly: composition children, read-only related entities, value helps and text entities — and understand how navigation properties are created or dropped.
Explanation
📌 KEY POINTS
✅ A navigation property exists only if both source and target are exposed in the same service.
✅ Composition children must be exposed and redirected in projections.
✅ Read-only related data (e.g. supplier) can be exposed via a read-only projection.
💡 Value-help entities used in annotations usually need to be reachable in the service.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Parts 1–5 designed services. This final part covers services with more than a root and its items: related entities, value helps and navigation rules.
━━━━━━━━━━━━━━━━━━━━
▶ 1. THE NAVIGATION RULE
For every association in an exposed projection, RAP checks: is the target also exposed (directly or as the redirected projection)?
- Yes → navigation property + NavigationPropertyBinding in $metadata; $expand works.
- No → the navigation is removed from the service.
This rule explains most "missing navigation" questions.
━━━━━━━━━━━━━━━━━━━━
▶ 2. COMPOSITION CHILDREN
- Expose every child projection the app needs.
- In projections, redirect: _Item : redirected to composition child ZC_PurchReqItem; _Request : redirected to parent ZC_PurchReq.
- Deep create (header + items in one request) works via the composition navigation.
━━━━━━━━━━━━━━━━━━━━
▶ 3. READ-ONLY RELATED ENTITIES
Example: the object page should link to supplier details.
- Create a simple read-only projection (e.g. ZC_SupplierRO on I_Supplier) with no behavior.
- In ZC_PurchReq, redirect _Supplier to it (or expose the association target directly).
- Expose it in the service. The supplier is readable, not changeable — no BDEF needed for read-only entities.
━━━━━━━━━━━━━━━━━━━━
▶ 4. VALUE HELPS
@Consumption.valueHelpDefinition on a field refers to an entity (e.g. I_Currency or a custom ZC_CurrencyVH).
- The value-help entity must be accessible to the service; RAP typically adds referenced value-help entities automatically when possible, but exposing a dedicated value-help view explicitly is the safest approach for custom views.
- Value-help views should be small, with a key, a text and @Search annotations for type-ahead.
━━━━━━━━━━━━━━━━━━━━
▶ 5. TEXT ENTITIES
Texts shown via text associations usually do not need exposing as separate entity sets; the text is delivered as a field. Expose text entities only if clients must read them directly.
━━━━━━━━━━━━━━━━━━━━
▶ 6. KEEP IT LEAN
Each exposed entity increases $metadata size and consumer surface. Expose what the app or API needs — not every association target in the model.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- List navigation the app needs: items (edit), supplier (read), value helps.
- Create read-only projection and value-help views.
- Redirect associations in ZC_PurchReq.
- Expose all targets in ZUI_PURCHREQ; check NavigationPropertyBinding entries in $metadata.
✅ CHECKPOINT: your service contains every entity and navigation the app needs — and nothing else. Next topic: Service Bindings.
Code example
// ===== Read-only projection for navigation =====@EndUserText.label: 'Supplier (read-only)'@AccessControl.authorizationCheck: #NOT_REQUIREDdefine view entity ZC_SupplierRO as projection on I_Supplier{ key Supplier, SupplierName, Country} // ===== Value-help view with search =====@EndUserText.label: 'Currency value help'@Search.searchable: true@AccessControl.authorizationCheck: #NOT_REQUIREDdefine view entity ZC_CurrencyVH as select from I_Currency{ @Search.defaultSearchElement: true key Currency, @Search.defaultSearchElement: true _Text[ 1: Language = $session.system_language ].CurrencyName as CurrencyName} // ===== Root projection: redirect compositions and references =====define root view entity ZC_PurchReq provider contract transactional_query as projection on ZR_PurchReq{ key RequestUUID, RequestID, Supplier, @Consumption.valueHelpDefinition: [{ entity: { name: 'ZC_CurrencyVH', element: 'Currency' } }] CurrencyCode, _Item : redirected to composition child ZC_PurchReqItem, _Supplier : redirected to ZC_SupplierRO // read-only navigation} // ===== Service: every navigation target exposed =====define service ZUI_PURCHREQ { expose ZC_PurchReq as PurchaseRequest; expose ZC_PurchReqItem as PurchaseRequestItem; expose ZC_SupplierRO as Supplier; // enables _Supplier navigation expose ZC_CurrencyVH as CurrencyValueHelp; // value help reachable} // $metadata check:// <NavigationPropertyBinding Path="_Item" Target="PurchaseRequestItem"/>// <NavigationPropertyBinding Path="_Supplier" Target="Supplier"/>Real project scenario
A purchase request app needed a supplier details link and a currency value help with type-ahead. The first attempt exposed the full supplier master projection with all its associations, which inflated $metadata and exposed more data than needed.
The team replaced it with a three-field read-only projection and a small searchable currency value-help view. Navigation and value help worked, $metadata stayed small, and the security review approved the service quickly because only the necessary supplier fields were visible.
Common mistakes
- Forgetting to expose navigation targets, so navigation disappears.
- Exposing large master-data projections instead of lean read-only ones.
- Value helps pointing to entities the service cannot reach.
- Not redirecting associations to the projections that are exposed.
- Exposing text entities that are not needed as entity sets.
Best practices
- Apply the navigation rule: expose source and target.
- Use lean read-only projections for related master data.
- Build dedicated, searchable value-help views.
- Redirect associations consistently in projections.
- Review $metadata size and content after each change.
Interview angle
Questions: "When does a RAP service contain a navigation property?", "How do you expose read-only related data?", "How do you provide a value help in a RAP service?"
Strong answer: navigation exists only if both source and target are exposed in the service (with redirection for projections); read-only related data via a lean projection without behavior, redirected and exposed; value helps via @Consumption.valueHelpDefinition on a reachable, searchable value-help view. Keep services lean for metadata size and security.
Practice this lesson
Quick check
1. When does a navigation property appear in a RAP OData service?
2. A service definition does not activate: "entity ZC_PurchReqItem not found". What should you do first?
3. A service exposes 18 helper entities "because every association might be needed". What is the best correction?
Interview questions
1. $expand on a supplier association fails in a RAP service, although the association exists in the projection. What is the cause?
Answer it in your own words first, then compare.
2. How do you expose related master data and value helps in a RAP service without bloating it?
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
- Service Definitions Part 1: What a Service Definition Does
- Service Definitions Part 2: Exposing Projection Entities as a Business Service
- Service Definitions Part 3: API Boundary, Naming and Versioning
- Service Definitions Part 4: Troubleshooting Activation and Exposure Gaps
- Service Definitions Part 5: UI vs Integration APIs — Reuse or Separate?