When developing Fiori Elements applications with the ABAP RESTful Application Programming Model (RAP), one of the key decisions is whether to go with Managed or Unmanaged implementation. In this blog, I’ll walk you through building a Fiori Elements app using Unmanaged RAP.
Unlike the managed scenario—where RAP automatically handles persistence and standard operations—Unmanaged RAP gives the developer full control over database interactions. This flexibility is especially useful when you need to handle complex business requirements such as:
Performing deep inserts, for example creating a main entity along with its related child entities in one request.Having fine-grained control over create, update, and delete logic.Defining custom actions tailored to specific business needs.
Another key concept here is RAP’s Logical Unit of Work (LUW). All changes are executed in a transactional way and only committed after validation checks pass. This ensures data consistency and is one of the main reasons why unmanaged RAP is often chosen in scenarios requiring complex persistence logic.
What we will be doing?
In this exercise, we will build an Unmanaged RAP app to create and modify records for a main entity along with its related child entities and Custom Action
By the end of this exercise, our List Report Page and Object Page will have the following capabilities and layout:
Deep Insert: Handle a main entity with related child entities in a single transaction.Full CRUD: Create, Read, Update, and Delete operations on both main and child entities, fully controlled by the developer.Association Handling: Use Create-by-Association (CBA) and Read-by-Association (RBA) for managing child entities in the Object Page.Custom Actions: Define business-specific actions that update both main and related entities.
We will be creating following objects –
Interface ViewProjection ViewMetadata ExtensionBehavior DefinitionBehavior ProjectionImplementation ClassService DefinitionService Binding
Steps to create unmanaged scenario based app
1) Interface Views :
Parent CDS view :
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view for Bookings’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_FlightBooking as select from zbooking_hdr
composition [1..*] of ZI_BookingPassenger as _Passengers
{
key booking_id,
customer_id,
flight_no,
booking_date,
status,
_Passengers
}
Child View :
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘interface view for booking passengers’
@Metadata.ignorePropagatedAnnotations: true
define view entity ZI_BookingPassenger
as select from zbooking_pass as _Passengers
association to parent ZI_FlightBooking as _Flightbooking on $projection.booking_id = _Flightbooking.booking_id
{
key booking_id,
key passenger_no,
name,
seat_no,
ticket_status,
_Flightbooking
}
Explanation:
The parent view ZI_FlightBooking represents the main booking entity, while the child view ZI_BookingPassenger represents the passengers associated with each booking. The child view has a direct association back to the parent, linking each passenger to its corresponding booking. This relationship allows the application to display and manage bookings together with their related passengers.
2) Projection Views :
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
@EndUserText.label: ‘Consumption view for flight bookings’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZC_FlightBooking
provider contract transactional_query
as projection on ZI_FlightBooking as _FlightBookings
{
key booking_id,
customer_id,
flight_no,
booking_date,
status,
/* Associations */
_Passengers : redirected to composition child ZC_BOOKINGPASSENGER
}@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption for flight bookings passengers’
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
@Metadata.ignorePropagatedAnnotations: true
define view entity ZC_BOOKINGPASSENGER
as projection on ZI_BookingPassenger
{
key booking_id,
key passenger_no,
name,
seat_no,
ticket_status,
/* Associations */
_Flightbooking : redirected to parent ZC_FlightBooking
}
3) Metadata Extensions :
@Metadata.layer: #CORE
@UI: {
headerInfo: {
typeName: ‘Flight Booking’,
typeNamePlural: ‘FLight Bookings’,
title: { value: ‘booking_id’ },
description: { value: ‘flight_no’ }
}
}
@Search.searchable: true
annotate entity ZC_FlightBooking with
{
.facet: [
{
id : ‘Passengers’,
label : ‘Passengers Details’,
type : #LINEITEM_REFERENCE,
position : 20,
targetElement : ‘_Passengers’
},
{
id: ‘Flight’,
purpose: #STANDARD,
position: 10,
label: ‘Flight Details’,
type: #IDENTIFICATION_REFERENCE
}
]
: {
lineItem: [ { position: 10, importance: #HIGH } ,
{ type: #FOR_ACTION , dataAction: ‘ConfirmTicket’, label: ‘CONFIRM’, position: 60 } ],
identification: [ { position: 10 }
]
}
.selectionField: [ { position: 10 } ]
.defaultSearchElement: true
.fieldGroup: [{ qualifier: ‘fgHeader’ , position: 10 }]
booking_id;
: {
lineItem: [ { position: 20, importance: #HIGH } ],
identification: [ { position: 20 } ]
}
.selectionField: [ { position: 20 } ]
.defaultSearchElement: true
.fieldGroup: [{ qualifier: ‘fgHeader’ , position: 20 }]
customer_id;
: {
lineItem: [ { position: 30, importance: #HIGH } ] ,
identification: [ { position: 30 } ] }
.defaultSearchElement: true
@EndUserText.label:’Flight Number’
.selectionField: [ { position: 30 } ]
flight_no;
: {
lineItem: [ { position: 40, importance: #HIGH } ]
}
.defaultSearchElement: true
.selectionField: [ { position: 40 } ]
@EndUserText.label:’Booking Date’
.fieldGroup: [{ qualifier: ‘fgHeader’ , position: 40 }]
booking_date;
: {
lineItem: [ { position: 50, importance: #HIGH } ],
identification: [ { position: 50 } ]
}
.selectionField: [ { position: 50 } ]
.defaultSearchElement: true
@EndUserText.label:’Status’
status;
}@Metadata.layer: #CORE
annotate entity ZC_BOOKINGPASSENGER
with
{
: { lineItem: [ { position: 10, importance: #HIGH } ] }
.identification: [{ position: 10 }]
passenger_no;
: { lineItem: [ { position: 20, importance: #HIGH } ]}
.identification: [{ position: 20 }]
name;
: { lineItem: [ { position: 30, importance: #HIGH } ] }
seat_no;
: { lineItem: [ { position: 40, importance: #HIGH } ] }
ticket_status;
}
4) Behavior Definition :
unmanaged implementation in class zbp_i_flightbooking unique;
strict ( 2 );
define behavior for ZI_FlightBooking //alias <alias_name>
//late numbering
lock master
authorization master ( instance )
//etag master <field_name>
{
create ( authorization : global );
update;
delete;
field ( readonly ) booking_id;
association _Passengers { create; }
action ConfirmTicket result [1] $self;
}
define behavior for ZI_BookingPassenger //alias <alias_name>
//late numbering
lock dependent by _Flightbooking
authorization dependent by _Flightbooking
//etag master <field_name>
{
create ;
update;
delete;
field ( readonly ) booking_id;
association _Flightbooking;
}
5) Behavior Projection
projection;
strict ( 2 );
define behavior for ZC_FlightBooking //alias <alias_name>
{
use create;
use update;
use delete;
use association _Passengers { create ; }
use action ConfirmTicket;
}
define behavior for ZC_BOOKINGPASSENGER //alias <alias_name>
{
use create ;
use update;
use delete;
use association _Flightbooking ;
}
6) Implementation Class :
CLASS lhc_ZI_FlightBooking DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR ZI_FlightBooking RESULT result.
METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR ZI_FlightBooking RESULT result.
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE ZI_FlightBooking.
METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE ZI_FlightBooking.
METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE ZI_FlightBooking.
METHODS read FOR READ
IMPORTING keys FOR READ ZI_FlightBooking RESULT result.
METHODS lock FOR LOCK
IMPORTING keys FOR LOCK ZI_FlightBooking.
METHODS rba_Passengers FOR READ
IMPORTING keys_rba FOR READ ZI_FlightBooking_Passengers FULL result_requested RESULT result LINK association_links.
METHODS cba_Passengers FOR MODIFY
IMPORTING entities_cba FOR CREATE ZI_FlightBooking_Passengers.
METHODS confirmBooking FOR MODIFY
IMPORTING keys FOR ACTION ZI_FlightBooking~ConfirmTicket RESULT result.
ENDCLASS.
CLASS lhc_ZI_FlightBooking IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD get_global_authorizations.
ENDMETHOD.
METHOD create.
LOOP AT entities INTO DATA(ls_booking).
” Build header work-area matching DB table structure and insert
DATA(ls_hdr) = VALUE zbooking_hdr(
booking_id = ls_booking-booking_id
customer_id = ls_booking-customer_id
flight_no = ls_booking-flight_no
booking_date = ls_booking-booking_date
status = ls_booking-status ).
INSERT zbooking_hdr FROM _hdr.
IF sy-subrc <> 0.
” handle failure (optional)
CONTINUE.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD update.
LOOP AT entities INTO DATA(ls_entity).
” Update booking header fields
UPDATE zbooking_hdr
SET customer_id = _entity-customer_id,
flight_no = _entity-flight_no,
booking_date = _entity-booking_date,
status = _entity-status
WHERE
booking_id = _entity-booking_id.
ENDLOOP.
ENDMETHOD.
METHOD delete.
LOOP AT keys ASSIGNING FIELD-SYMBOL(<ls_key>).
” Delete from DB table
DELETE FROM zbooking_hdr
WHERE booking_id = @<ls_key>-booking_id.
IF sy-subrc <> 0.
” Raise RAP message if record not found
APPEND VALUE #( %msg = new_message(
id = ‘ZBOOKING_MSG’
number = ‘001’
severity = if_abap_behv_message=>severity-error
v1 = <ls_key>-booking_id ) ) TO reported-zi_flightbooking.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD read.
LOOP AT keys INTO DATA(ls_key).
“Fetch header record
SELECT SINGLE mandt,
booking_id,
customer_id,
flight_no,
booking_date,
status
FROM zbooking_hdr
WHERE booking_id = _key-booking_id
INTO (ls_hdr).
IF sy-subrc = 0.
APPEND VALUE #( %tky = ls_key-%tky
* mandt = ls_hdr-mandt
booking_id = ls_hdr-booking_id
customer_id = ls_hdr-customer_id
flight_no = ls_hdr-flight_no
booking_date = ls_hdr-booking_date
status = ls_hdr-status ) TO result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD lock.
ENDMETHOD.
METHOD rba_Passengers.
DATA lt_pass TYPE STANDARD TABLE OF zbooking_pass.
” Read passengers for the given booking IDs
SELECT * FROM zbooking_pass
FOR ALL ENTRIES IN _rba
WHERE booking_id = _rba-booking_id
INTO TABLE _pass.
” Map DB results to RAP result
result = CORRESPONDING #( lt_pass ).
ENDMETHOD.
METHOD cba_Passengers.
LOOP AT entities_cba INTO DATA(ls_entity).
LOOP AT ls_entity-%target INTO DATA(ls_pass).
” Generate new passenger number (simple approach)
DATA(lv_new_pass_no) = sy-tabix. ” Better: use number range or UUID
DATA(ls_booking) = VALUE zbooking_pass(
booking_id = ls_pass-booking_id
passenger_no = lv_new_pass_no
name = ls_pass-name
seat_no = ls_pass-seat_no
ticket_status = ls_pass-ticket_status
).
INSERT zbooking_pass FROM ls_booking.
IF sy-subrc <> 0.
” handle failure (optional)
CONTINUE.
ENDIF.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
METHOD confirmBooking.
LOOP AT keys ASSIGNING FIELD-SYMBOL(<ls_key>).
” 1. Update booking header
UPDATE zbooking_hdr
SET status = ‘CONFIRMED’
WHERE booking_id = <ls_key>-booking_id.
” 2. Update dependent passengers
UPDATE zbooking_pass
SET ticket_status = ‘CONFIRMED’
WHERE booking_id = <ls_key>-booking_id.
” 3. Return updated header so UI refreshes
APPEND VALUE #( booking_id = <ls_key>-booking_id ) TO result.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
7) Service Definition :
@EndUserText.label: ‘Service Defination for Flight bookings’
define service ZSD_FLIGHTSBOOKINGS {
expose ZC_BOOKINGPASSENGER;
expose ZC_FlightBooking;
}
😎Service Binding :
Create a Service Binding on top of the Service Definition, selecting OData V2 – UI service. Activate and publish it.
Once completed, preview the entity and test all functionalities, you now have a working service!
Preview of RAP app :
When we open a record and click EDIT, both the parent and child entities are updated together in a single operation.
When the user clicks the Confirm Bookings action, the status of the booking header as well as all associated passengers is updated simultaneously.
When developing Fiori Elements applications with the ABAP RESTful Application Programming Model (RAP), one of the key decisions is whether to go with Managed or Unmanaged implementation. In this blog, I’ll walk you through building a Fiori Elements app using Unmanaged RAP.Unlike the managed scenario—where RAP automatically handles persistence and standard operations—Unmanaged RAP gives the developer full control over database interactions. This flexibility is especially useful when you need to handle complex business requirements such as:Performing deep inserts, for example creating a main entity along with its related child entities in one request.Having fine-grained control over create, update, and delete logic.Defining custom actions tailored to specific business needs.Another key concept here is RAP’s Logical Unit of Work (LUW). All changes are executed in a transactional way and only committed after validation checks pass. This ensures data consistency and is one of the main reasons why unmanaged RAP is often chosen in scenarios requiring complex persistence logic.What we will be doing?In this exercise, we will build an Unmanaged RAP app to create and modify records for a main entity along with its related child entities and Custom ActionBy the end of this exercise, our List Report Page and Object Page will have the following capabilities and layout:Deep Insert: Handle a main entity with related child entities in a single transaction.Full CRUD: Create, Read, Update, and Delete operations on both main and child entities, fully controlled by the developer.Association Handling: Use Create-by-Association (CBA) and Read-by-Association (RBA) for managing child entities in the Object Page.Custom Actions: Define business-specific actions that update both main and related entities.We will be creating following objects –Interface ViewProjection ViewMetadata ExtensionBehavior DefinitionBehavior ProjectionImplementation ClassService DefinitionService BindingSteps to create unmanaged scenario based app1) Interface Views : Parent CDS view : @AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view for Bookings’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZI_FlightBooking as select from zbooking_hdr
composition [1..*] of ZI_BookingPassenger as _Passengers
{
key booking_id,
customer_id,
flight_no,
booking_date,
status,
_Passengers
} Child View :@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘interface view for booking passengers’
@Metadata.ignorePropagatedAnnotations: true
define view entity ZI_BookingPassenger
as select from zbooking_pass as _Passengers
association to parent ZI_FlightBooking as _Flightbooking on $projection.booking_id = _Flightbooking.booking_id
{
key booking_id,
key passenger_no,
name,
seat_no,
ticket_status,
_Flightbooking
} Explanation:The parent view ZI_FlightBooking represents the main booking entity, while the child view ZI_BookingPassenger represents the passengers associated with each booking. The child view has a direct association back to the parent, linking each passenger to its corresponding booking. This relationship allows the application to display and manage bookings together with their related passengers.2) Projection Views : @AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
@EndUserText.label: ‘Consumption view for flight bookings’
@Metadata.ignorePropagatedAnnotations: true
define root view entity ZC_FlightBooking
provider contract transactional_query
as projection on ZI_FlightBooking as _FlightBookings
{
key booking_id,
customer_id,
flight_no,
booking_date,
status,
/* Associations */
_Passengers : redirected to composition child ZC_BOOKINGPASSENGER
}@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption for flight bookings passengers’
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
@Metadata.ignorePropagatedAnnotations: true
define view entity ZC_BOOKINGPASSENGER
as projection on ZI_BookingPassenger
{
key booking_id,
key passenger_no,
name,
seat_no,
ticket_status,
/* Associations */
_Flightbooking : redirected to parent ZC_FlightBooking
} 3) Metadata Extensions :@Metadata.layer: #CORE
@UI: {
headerInfo: {
typeName: ‘Flight Booking’,
typeNamePlural: ‘FLight Bookings’,
title: { value: ‘booking_id’ },
description: { value: ‘flight_no’ }
}
}
@Search.searchable: true
annotate entity ZC_FlightBooking with
{
.facet: [
{
id : ‘Passengers’,
label : ‘Passengers Details’,
type : #LINEITEM_REFERENCE,
position : 20,
targetElement : ‘_Passengers’
},
{
id: ‘Flight’,
purpose: #STANDARD,
position: 10,
label: ‘Flight Details’,
type: #IDENTIFICATION_REFERENCE
}
]
: {
lineItem: [ { position: 10, importance: #HIGH } ,
{ type: #FOR_ACTION , dataAction: ‘ConfirmTicket’, label: ‘CONFIRM’, position: 60 } ],
identification: [ { position: 10 }
]
}
.selectionField: [ { position: 10 } ]
.defaultSearchElement: true
.fieldGroup: [{ qualifier: ‘fgHeader’ , position: 10 }]
booking_id;
: {
lineItem: [ { position: 20, importance: #HIGH } ],
identification: [ { position: 20 } ]
}
.selectionField: [ { position: 20 } ]
.defaultSearchElement: true
.fieldGroup: [{ qualifier: ‘fgHeader’ , position: 20 }]
customer_id;
: {
lineItem: [ { position: 30, importance: #HIGH } ] ,
identification: [ { position: 30 } ] }
.defaultSearchElement: true
@EndUserText.label:’Flight Number’
.selectionField: [ { position: 30 } ]
flight_no;
: {
lineItem: [ { position: 40, importance: #HIGH } ]
}
.defaultSearchElement: true
.selectionField: [ { position: 40 } ]
@EndUserText.label:’Booking Date’
.fieldGroup: [{ qualifier: ‘fgHeader’ , position: 40 }]
booking_date;
: {
lineItem: [ { position: 50, importance: #HIGH } ],
identification: [ { position: 50 } ]
}
.selectionField: [ { position: 50 } ]
.defaultSearchElement: true
@EndUserText.label:’Status’
status;
}@Metadata.layer: #CORE
annotate entity ZC_BOOKINGPASSENGER
with
{
: { lineItem: [ { position: 10, importance: #HIGH } ] }
.identification: [{ position: 10 }]
passenger_no;
: { lineItem: [ { position: 20, importance: #HIGH } ]}
.identification: [{ position: 20 }]
name;
: { lineItem: [ { position: 30, importance: #HIGH } ] }
seat_no;
: { lineItem: [ { position: 40, importance: #HIGH } ] }
ticket_status;
}4) Behavior Definition :unmanaged implementation in class zbp_i_flightbooking unique;
strict ( 2 );
define behavior for ZI_FlightBooking //alias <alias_name>
//late numbering
lock master
authorization master ( instance )
//etag master <field_name>
{
create ( authorization : global );
update;
delete;
field ( readonly ) booking_id;
association _Passengers { create; }
action ConfirmTicket result [1] $self;
}
define behavior for ZI_BookingPassenger //alias <alias_name>
//late numbering
lock dependent by _Flightbooking
authorization dependent by _Flightbooking
//etag master <field_name>
{
create ;
update;
delete;
field ( readonly ) booking_id;
association _Flightbooking;
}5) Behavior Projectionprojection;
strict ( 2 );
define behavior for ZC_FlightBooking //alias <alias_name>
{
use create;
use update;
use delete;
use association _Passengers { create ; }
use action ConfirmTicket;
}
define behavior for ZC_BOOKINGPASSENGER //alias <alias_name>
{
use create ;
use update;
use delete;
use association _Flightbooking ;
} 6) Implementation Class :CLASS lhc_ZI_FlightBooking DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR ZI_FlightBooking RESULT result.
METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING REQUEST requested_authorizations FOR ZI_FlightBooking RESULT result.
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE ZI_FlightBooking.
METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE ZI_FlightBooking.
METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE ZI_FlightBooking.
METHODS read FOR READ
IMPORTING keys FOR READ ZI_FlightBooking RESULT result.
METHODS lock FOR LOCK
IMPORTING keys FOR LOCK ZI_FlightBooking.
METHODS rba_Passengers FOR READ
IMPORTING keys_rba FOR READ ZI_FlightBooking_Passengers FULL result_requested RESULT result LINK association_links.
METHODS cba_Passengers FOR MODIFY
IMPORTING entities_cba FOR CREATE ZI_FlightBooking_Passengers.
METHODS confirmBooking FOR MODIFY
IMPORTING keys FOR ACTION ZI_FlightBooking~ConfirmTicket RESULT result.
ENDCLASS.
CLASS lhc_ZI_FlightBooking IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD get_global_authorizations.
ENDMETHOD.
METHOD create.
LOOP AT entities INTO DATA(ls_booking).
” Build header work-area matching DB table structure and insert
DATA(ls_hdr) = VALUE zbooking_hdr(
booking_id = ls_booking-booking_id
customer_id = ls_booking-customer_id
flight_no = ls_booking-flight_no
booking_date = ls_booking-booking_date
status = ls_booking-status ).
INSERT zbooking_hdr FROM _hdr.
IF sy-subrc <> 0.
” handle failure (optional)
CONTINUE.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD update.
LOOP AT entities INTO DATA(ls_entity).
” Update booking header fields
UPDATE zbooking_hdr
SET customer_id = _entity-customer_id,
flight_no = _entity-flight_no,
booking_date = _entity-booking_date,
status = _entity-status
WHERE
booking_id = _entity-booking_id.
ENDLOOP.
ENDMETHOD.
METHOD delete.
LOOP AT keys ASSIGNING FIELD-SYMBOL(<ls_key>).
” Delete from DB table
DELETE FROM zbooking_hdr
WHERE booking_id = @<ls_key>-booking_id.
IF sy-subrc <> 0.
” Raise RAP message if record not found
APPEND VALUE #( %msg = new_message(
id = ‘ZBOOKING_MSG’
number = ‘001’
severity = if_abap_behv_message=>severity-error
v1 = <ls_key>-booking_id ) ) TO reported-zi_flightbooking.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD read.
LOOP AT keys INTO DATA(ls_key).
“Fetch header record
SELECT SINGLE mandt,
booking_id,
customer_id,
flight_no,
booking_date,
status
FROM zbooking_hdr
WHERE booking_id = _key-booking_id
INTO (ls_hdr).
IF sy-subrc = 0.
APPEND VALUE #( %tky = ls_key-%tky
* mandt = ls_hdr-mandt
booking_id = ls_hdr-booking_id
customer_id = ls_hdr-customer_id
flight_no = ls_hdr-flight_no
booking_date = ls_hdr-booking_date
status = ls_hdr-status ) TO result.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD lock.
ENDMETHOD.
METHOD rba_Passengers.
DATA lt_pass TYPE STANDARD TABLE OF zbooking_pass.
” Read passengers for the given booking IDs
SELECT * FROM zbooking_pass
FOR ALL ENTRIES IN _rba
WHERE booking_id = _rba-booking_id
INTO TABLE _pass.
” Map DB results to RAP result
result = CORRESPONDING #( lt_pass ).
ENDMETHOD.
METHOD cba_Passengers.
LOOP AT entities_cba INTO DATA(ls_entity).
LOOP AT ls_entity-%target INTO DATA(ls_pass).
” Generate new passenger number (simple approach)
DATA(lv_new_pass_no) = sy-tabix. ” Better: use number range or UUID
DATA(ls_booking) = VALUE zbooking_pass(
booking_id = ls_pass-booking_id
passenger_no = lv_new_pass_no
name = ls_pass-name
seat_no = ls_pass-seat_no
ticket_status = ls_pass-ticket_status
).
INSERT zbooking_pass FROM ls_booking.
IF sy-subrc <> 0.
” handle failure (optional)
CONTINUE.
ENDIF.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
METHOD confirmBooking.
LOOP AT keys ASSIGNING FIELD-SYMBOL(<ls_key>).
” 1. Update booking header
UPDATE zbooking_hdr
SET status = ‘CONFIRMED’
WHERE booking_id = <ls_key>-booking_id.
” 2. Update dependent passengers
UPDATE zbooking_pass
SET ticket_status = ‘CONFIRMED’
WHERE booking_id = <ls_key>-booking_id.
” 3. Return updated header so UI refreshes
APPEND VALUE #( booking_id = <ls_key>-booking_id ) TO result.
ENDLOOP.
ENDMETHOD.
ENDCLASS. 7) Service Definition :@EndUserText.label: ‘Service Defination for Flight bookings’
define service ZSD_FLIGHTSBOOKINGS {
expose ZC_BOOKINGPASSENGER;
expose ZC_FlightBooking;
}😎Service Binding :Create a Service Binding on top of the Service Definition, selecting OData V2 – UI service. Activate and publish it.Once completed, preview the entity and test all functionalities, you now have a working service!Preview of RAP app :When we open a record and click EDIT, both the parent and child entities are updated together in a single operation.When the user clicks the Confirm Bookings action, the status of the booking header as well as all associated passengers is updated simultaneously. Read More Technology Blog Posts by SAP articles
#SAP
#SAPTechnologyblog