Learn SAP from the Experts | The SAP PRESS Blog

Managing Recursive Data Structures with SAP RAP and Fiori Elements

Written by Monalisa Biswal | Jul 17, 2026 1:00:03 PM

Not all business data fits neatly into flat tables. Product catalogs, org charts, and account structures often rely on parent-child relationships that standard data models can't represent well.

 

For example, in a grocery retail scenario, products may need to be grouped across multiple levels such as department, category, subcategory, and item, so that business users can maintain product structures consistently in one application.

 

This is a good fit for the ABAP RESTful application programming model (RAP), because RAP provides a structured way to model transactional business objects, define parent-child compositions, enable draft handling, expose OData V4 services, and generate an SAP Fiori elements-based user experience with less custom code.

 

Consider a common grocery item such as “Gala Apple 1kg.” The following example shows how its hierarchy can be modeled and managed in the system.

 

Hier Type

Hier Value

Parent

Computed Hierarchy Path

DEPT

Food

Food

CAT

Fresh Produce

Food

Food → Fresh Produce

SUBCAT

Fruits

Fresh Produce

Food → Fresh Produce → Fruits

ITEM

Apples

Fruits

Food → Fresh Produce → Fruits → Apples

 

Because each hierarchy node can be a child of a higher-level node and a parent of lower-level nodes, the model is recursive. A standard flat data model cannot represent this structure effectively. The solution requires a self-referencing table and a framework that can safely manage the transactional complexity of editing hierarchical data.

 

This post will explain how RAP can be applied to this grocery store product hierarchy use case—a relatable and practical scenario that demonstrates the key concepts without adding unnecessary domain complexity.

 

Solution Architecture

The application that we’ll use follows the standard RAP-layered architecture. Each layer has a clear responsibility, which makes the solution easier to maintain, test, and extend while aligning with SAP clean core principles for custom development.

 

Layer

Artifact

Purpose

Persistence

ZPRODUCT_HDR ZPRODUCT_HIER

Database storage for products and hierarchy nodes

Base CDS

ZI_Product_B ZI_ProductHierarchy_B

Semantic field aliases + hierarchy path computation

Interface CDS

ZI_Product_I ZI_ProductHierarchy_I

RAP root entity + composition + associations

Consumption CDS

ZC_Product ZC_ProductHierarchy

SAP Fiori-ready projection + association redirects

Behavior Def.

BDEF on ZI_Product_I

CRUD, draft lifecycle, managed numbering

Service Layer

ZUI_PRODUCT_O4 (Def. + Binding)

OData V4 exposure for SAP Fiori elements

UI Annotations

MDE on ZC_Product MDE on ZC_ProductHierarchy

SAP Fiori elements layout metadata

 

In RAP, the interface CDS views define the business object boundary. The consumption CDS views shape data for the UI. The behavior definition controls what operations are allowed and how data is persisted. These three concerns are always kept in separate artifacts.

 

Data Model

The solution is built on two database tables. The product header table stores the product master record, while the hierarchy table stores hierarchy nodes with a self-referencing foreign key that establishes the parent–child relationship between nodes.

 

Note that draft tables (suffix _D) for both tables are generated automatically by the ABAP system when the behavior definition is activated. They do not need to be created manually.

 

CDS views play a central role in defining the hierarchical structure. The following sample illustrates how product hierarchies can be modeled and managed effectively.

 

RAP Interface Views

Interface views define the structure of the RAP business object. The root entity declares the composition to the child entity, while the child entity declares back-associations and self-associations for parent and child navigation.

ZI_Product_I — Root Entity

define root view entity ZI_Product_I

    as select from ZI_Product_B

     composition [0..*] of ZI_ProductHierarchy_I as _Hierarchy

     association [0..*] to ZI_Product_B as _ProductType

         on $projection.ProductType = _ProductType.ProductType

{

     key ProductID,

         ProductName,

 

         @ObjectModel.foreignKey.association: '_ProductType'

         ProductType,

 

         ProductImageUrl,

         LastChangedAt,

         LocalLastChangedAt,

         _Hierarchy,

         _ProductType

}

 

The composition [0..*] declaration makes ZI_ProductHierarchy_I a child entity of this root. All hierarchy nodes for a product are managed as part of the same transactional business object and share the same lock.

ZI_ProductHierarchy_I — Child Entity

The child view exposes hierarchy node data and declares three associations: a parent back-association to the root product, and two self-associations for upward (_Parent) and downward (_Children) navigation within the hierarchy.

 

define view entity ZI_ProductHierarchy_I

     as select from ZI_ProductHierarchy_B

     association to parent ZI_Product_I         as _Product

        on $projection.ProductID      = _Product.ProductID

     association [0..1] to ZI_ProductHierarchy_I as _Parent

         on $projection.ParentHierID  = _Parent.HierID

         and $projection.ProductID    = _Parent.ProductID

     association [0..*] to ZI_ProductHierarchy_I as _Children

         on $projection.HierID        = _Children.ParentHierID

         and $projection.ProductID    = _Children.ProductID

{

     key HierID,

         ProductID,

         ParentHierID,

         HierType,

         HierValue,

         HierarchyPath,

         LastChangedAt,

         LocalLastChangedAt,

         _Product,

         _Parent,

         _Children

}

 

Consumption Views

Consumption views project from interface views and redirect associations to their consumption counterparts. This completes the RAP composition chain and makes the entities SAP Fiori-ready.

ZC_Product

@Metadata.allowExtensions: true

 

@UI.headerInfo: {

    typeName:       'Product',

    typeNamePlural: 'Products',

     title:       { value: 'ProductName' },

     description: { value: 'ProductType' },

     imageUrl: 'ProductImageUrl'

}

 

define root view entity ZC_Product

     provider contract transactional_query

     as projection on ZI_Product_I

{

     key ProductID,

         ProductName,

         ProductType,

 

         @Semantics.imageUrl: true

         ProductImageUrl,

 

         _Hierarchy : redirected to composition child ZC_ProductHierarchy

}

ZC_ProductHierarchy

@Metadata.allowExtensions: true

 

define view entity ZC_ProductHierarchy

     as projection on ZI_ProductHierarchy_I

{

     @ObjectModel.text.element: [ 'HierValue' ]

     key HierID,

         ProductID,

 

         @ObjectModel.text.element: [ 'ParentHierValue' ]

         ParentHierID,

         _Parent.HierValue as ParentHierValue,

 

         HierType,

         HierValue,

         HierarchyPath,

 

         _Product : redirected to parent ZC_Product,

         _Parent : redirected to ZC_ProductHierarchy,

         _Children : redirected to ZC_ProductHierarchy

}

 

Behavior Definition

The behavior definition specifies the transactional capabilities of the RAP business object. This solution uses a managed implementation with draft support. The two entities—Product as the root and Hierarchy Node as the child—serve different roles and therefore require different behavior settings.

 

Aspect

Product Entity

Hierarchy Entity

Entity

ZI_Product_I (Product)

ZI_ProductHierarchy_I (Hierarchy Node)

Role

Lock master — owns the draft lifecycle

Lock dependent — inherits lock from Product

Persistent Table

ZPRODUCT_HDR

ZPRODUCT_HIER

Draft Table

ZPRODUCT_HDR_D (auto-generated)

ZPRODUCT_HIER_D (auto-generated)

Operations

create, update, delete

update, delete (create via composition)

Draft Actions

Edit, Resume, Prepare, Activate optimized, Discard

Inherited from root; with draft on _Product

Key Numbering

product_id — user-provided

hier_id — managed (UUID auto-generated by RAP)

Association

_Hierarchy { create; with draft; }

_Product, _Parent, _Children

Lock Strategy

total etag on LastChangedAt

etag master on LocalLastChangedAt

 

The most important design decisions in the behavior definition are:

  • Draft with "Activate optimized": Reduces database write operations during save by batching changes. Recommended for all new RAP draft implementations.
  • association _Hierarchy { create; with draft; }: Allows hierarchy nodes to be created within the same product edit session, making the product and its hierarchy nodes a single atomic operation.
  • field (numbering: managed) HierID: The framework auto-generates a UUID for each new hierarchy node. Users never see or enter this key.
  • lock dependent by _Product: The hierarchy entity inherits its lock from the product root. Only one editor can modify a product and its hierarchy at a time.

UI and Service Layer

The service definition and metadata annotation extensions complete the application stack. The service definition specifies which entities are exposed through OData V4, while the annotation extensions define how SAP Fiori elements renders those entities in the list report and object page.

 

Here’s an example of a list page:

 


 

And here’s an example of an object page:

 

Service Entities (ZUI_PRODUCT_O4)

The service definition exposes four entities. Two are transactional and two serve value help purposes only:

 

Entity

Role

Purpose

ZC_Product

Transactional (Root)

Main entry point for the SAP Fiori application. Exposes the product list report and object page.

ZC_ProductHierarchy

Transactional (Child)

Exposes hierarchy nodes within the product object page via the composition association.

ZI_Product_B

Value Help

Provides the ProductType value help in the product creation and edit forms.

ZI_ParentHierVH

Value Help

Provides the parent hierarchy node selection, scoped by ProductID to prevent cross-product assignments.

 

A best practice is to expose only the entities the UI actually needs. Unnecessary entity exposure increases the attack surface of the service and can degrade OData metadata performance in large landscapes.

UI Annotation Patterns

Metadata extension files apply UI annotations to the consumption views without modifying the CDS views themselves. The table below shows some sample annotations used in the application.

 

Annotation

Applied To

Value/Setting

Effect in SAP Fiori Elements
@UI.facet Both views

#IDENTIFICATION_REFERENCE

#LINEITEM_REFERENCE

Groups fields into object page sections.
@UI.lineItem Both views position: 10, 20, 30 Controls which fields appear as columns in the list report table and the hierarchy items embedded table. 
@UI.selectionField Both views position: 10, 20, 30 Adds fields to the filter bar above the list report.
@UI.identification Both views position: 10, 20, 30 Places fields in the General Information section on the object page.
@UI.textArrangement

ProductType

ParentHierID

#TEXT_ONLY Hides the raw key value and shows only the descriptive text in the UI field.
@Consumption.valueHelpDefinition

ProductType

ParentHierID

ZI_Product_B

ZI_ParentHierVH

Shows a value help dialog to the field. Parent hierarchy help uses additionalBinding to scope by ProductID.
@UI.hidden ParentHierValue true Keeps the derived text field invisible in the UI while still available for text resolution via @ObjectModel.text.element. 
@Semantics.imageUrl ProductImageUrl   Tells SAP Fiori elements to render the field value as an image URL and display the image thumbnail in the list.

 

Key Takeaways

The following points highlight the most important aspects of this solution.

  1. Recursive hierarchies need only one table. A single self-referencing foreign key (parent_hier_id → hier_id) is sufficient to model unlimited depth. The CDS layer handles path computation — no additional tables are needed.
  2. CDS self-joins compute paths declaratively. Up to four ancestor levels can be traversed using left outer self-joins and CASE/CONCAT expressions in a base CDS view. No ABAP code is needed for path calculation.
  3. CDS views are organized across three layers. Base views provide the semantic model and computed fields, interface views define the RAP business object, and consumption views shape the data for SAP Fiori. Each layer has a clearly defined responsibility.
  4. Managed RAP with draft eliminates custom boilerplate. Locking, draft tables, activation, and discard are all framework-managed. The developer declares intent in the behavior definition; the framework executes it.
  5. Composition makes hierarchies transactional. Declaring a composition between Product and Hierarchy Node means all changes to both entities are committed or rolled back together in one Activate action.
  6. Metadata extensions keep UI and data model separate. Annotation files can evolve independently, be transported separately, and be adjusted for different UI scenarios without touching the CDS views.

This post was originally published 7/2026.