Implementing Unmanaged CRUD Operations in SAP RAP: A Hands-On Guide

Estimated read time 22 min read

 In this blog, I’m going to walk you through how to implement unmanaged CRUD operations in SAP RAP for an on-premise system. We’ll be using a simple employee management example to cover the basics of creating, updating, and deleting employee records.

By the end of this post, you’ll understand how to work with CRUD operations in the RAP framework and get hands-on experience with it. I’ve been working on this project recently, and I figured it would be useful to share the process with you.

Just a quick note: I’ve been using AI (like GenAI) to help with writing content for this blog. It’s been super helpful for organizing thoughts and getting content down quickly while I focus on the technical stuff. AI’s a great tool for speeding up writing, and I think it’s worth mentioning how it’s making content creation a bit easier for me.

Visual Structure Example:

+—————————————+
| Step 1: Create Database Table |
+—————————————+
|
V
+—————————————+
| Step 2: Create Root View |
+—————————————+
|
V
+—————————————+
| Step 3: Create Projection View |
+—————————————+
|
V
+—————————————+
| Step 4: Create Behavior Definition |
+—————————————+
|
V
+—————————————+
| Step 5: Create Behavior for Projection|
+—————————————+
|
V
+—————————————+
| Step 6: Create Metadata Extension |
+—————————————+
|
V
+—————————————+
| Step 7: Implement CRUD Logic |
+—————————————+
|
V
+—————————————+
| Step 8: Create Service Definition |
+—————————————+
|
V
+—————————————+
| Step 9: Bind the Service |
+—————————————+
|
V
+—————————————+
| Step 10: Test CRUD Operations |
+—————————————+

Step 1: Create a Database Table

Here, we create a table in the database that stores employee information like employee ID, name, email, salary, etc. We use special annotations to tell SAP how this table should be used.

@EndUserText.label : ‘Employee Table’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zun_emp_tab {
key client : abap.clnt not null;
key emp_id : zempid not null;
first_name : abap.char(30);
last_name : abap.char(30);
date_of_birth : abap.dats;
email : abap.sstring(60);
hire_date : abap.dats;
@Semantics.amount.currencyCode : ‘zun_emp_tab.curry’
salary : abap.curr(15,2);
curry : abap.cuky;
}

Step 2: Create a Root View for the Table

The Root View is like a connection between the database table and the system. It allows the data to be used for CRUD operations.

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view’
@Metadata.ignorePropagatedAnnotations: true
define root view entity zun_emp_root as select from zun_emp_tab
{
key emp_id as EmpId,
first_name as FirstName,
last_name as LastName,
date_of_birth as DateOfBirth,
email as Email,
hire_date as HireDate,
@Semantics.amount.currencyCode: ‘curry’
salary as Salary,
curry as Curry
}

Step 3: Create a Projection View for the Root View

A Projection View is a simplified version of the Root View, designed specifically for consumption in applications. It lets users view and edit employee information in a user-friendly format.

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity zun_emp_proj as projection on zun_emp_root
{
key EmpId,
FirstName,
LastName,
DateOfBirth,
Email,
HireDate,
@Semantics.amount.currencyCode: ‘Curry’
Salary,
Curry
}

Step 4: Create Behavior Definition for the Root View

This is where we define what can happen to the data (create, update, delete). We set permissions and behaviors for each operation.

unmanaged implementation in class zbp_un_emp_root unique;
strict ( 2 );
define behavior for zun_emp_root alias EMP
late numbering
lock master
authorization master ( instance )
//etag master <field_name>
{
create;
update;
delete;
}

Step 5: Create Behavior Definition for the Projection View

Similar to the Root View, we define behavior for the Projection View, ensuring that data can be created, updated, and deleted in the UI.

projection;
strict ( 2 );

define behavior for zun_emp_proj alias EMP
{
use create;
use update;
use delete;
}

Step 6: Create a Metadata Extension for the Projection View

Here, we enhance the UI by adding labels, fields, and other settings so users can easily interact with the employee data.

@Metadata.layer: #CUSTOMER

@UI.headerInfo: {
typeName: ‘Employee’,
typeNamePlural: ‘Employees’,
title: {
type: #STANDARD,
label: ‘Employee ID’,
value: ‘EmpId’
},
description: {
label: ‘First Name’,
value: ‘FirstName’
}
}

annotate view zun_emp_proj with {

//=========================
// Facets (sections)
//=========================
.facet: [
{
id: ‘GeneralInfo’,
type: #IDENTIFICATION_REFERENCE,
label: ‘General Information’,
position: 10
}
]

//=========================
// General Information Fields
//=========================
.identification: [{ position: 10, label: ‘Employee ID’ }]
.selectionField: [{ position: 10 }]
.lineItem: [{ position: 10 }]
@EndUserText.label: ‘Employee ID’
EmpId;

.identification: [{ position: 20, label: ‘First Name’ }]
.selectionField: [{ position: 20 }]
.lineItem: [{ position: 20 }]
@EndUserText.label: ‘First Name’
FirstName;

.identification: [{ position: 30, label: ‘Last Name’ }]
.selectionField: [{ position: 30 }]
.lineItem: [{ position: 30 }]
@EndUserText.label: ‘Last Name’
LastName;

.identification: [{ position: 40, label: ‘Date of Birth’ }]
.lineItem: [{ position: 40 }]
.selectionField: [{ position: 40 }]
@EndUserText.label: ‘Date of Birth’
DateOfBirth;

.identification: [{ position: 50, label: ‘Email’ }]
.lineItem: [{ position: 50 }]
@EndUserText.label: ‘Email’
Email;

.identification: [{ position: 60, label: ‘Hire Date’ }]
.selectionField: [{ position: 50 }]
.lineItem: [{ position: 60 }]
@EndUserText.label: ‘Hire Date’
HireDate;

.identification: [{ position: 70, label: ‘Salary’ }]
.lineItem: [{ position: 70 }]
@EndUserText.label: ‘Salary’
Salary;

.identification: [{ position: 80, label: ‘Currency’ }]
.lineItem: [{ position: 80 }]
@EndUserText.label: ‘Currency’
Curry;

};

Step 7: Implement the Logic for CRUD Operations

We write the logic that handles creating, updating, and deleting employee records. We use three key components:

Handler Class: This is where the main logic for CRUD operations happens.

Saver Class: This class saves the changes to the database.

Buffer Class: This is like a temporary holding place for changes before they are saved to the database.

Simplified Diagram:

+——————+ –> (Create, Update, Delete)
| User Request |
+——————+
|
V
+——————-+ –> (Handler Class) –> +———————+
| Handler Class | ——————–> | Buffer Class |
+——————-+ +———————+
| |
V V
+———————+ +———————+
| Data Saved in DB | <– (Saver Class) <– | Database (Employee Data) |
+———————+ +———————+

While practicing, you shouldn’t just copy-paste the code. You should write it yourself to get hands-on experience.

” Buffer class to hold create/update/delete entries temporarily
CLASS lcl_buffer DEFINITION CREATE PRIVATE.
PUBLIC SECTION.
TYPES: BEGIN OF ty_buffer,
flag TYPE c LENGTH 1, ” ‘C’ = Create, ‘U’ = Update, ‘D’ = Delete
lv_data TYPE zun_emp_tab, ” The structure that holds employee data
END OF ty_buffer.

CLASS-DATA mt_buffer TYPE STANDARD TABLE OF ty_buffer WITH EMPTY KEY. ” Table to store buffer entries

” Method to get an instance of the buffer class (Singleton pattern)
CLASS-METHODS get_instance
RETURNING VALUE(ro_instance) TYPE REF TO lcl_buffer.

” Method to add records to the buffer (Create, Update, or Delete)
METHODS add_to_buffer
IMPORTING
iv_flag TYPE c ” Flag to specify the type of operation (C/U/D)
is_employee TYPE zun_emp_tab. ” Employee data to be added to the buffer

PRIVATE SECTION.
CLASS-DATA go_instance TYPE REF TO lcl_buffer. ” Holds the single instance of the class
ENDCLASS.

CLASS lcl_buffer IMPLEMENTATION.

METHOD get_instance.
IF go_instance IS NOT BOUND.
go_instance = NEW #( ).
ENDIF.
ro_instance = go_instance.
ENDMETHOD.

METHOD add_to_buffer.
INSERT VALUE #( flag = iv_flag lv_data = is_employee ) INTO TABLE mt_buffer.
ENDMETHOD.

ENDCLASS.

” Custom Exception Class
CLASS zcx_my_exception DEFINITION INHERITING FROM cx_static_check.
PUBLIC SECTION.
INTERFACES if_t100_message. ” This interface is used for handling messages.
METHODS constructor IMPORTING
textid LIKE if_t100_message=>t100key OPTIONAL. ” Constructor to initialize exception with a message
ENDCLASS.

CLASS zcx_my_exception IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor
EXPORTING
previous = previous. ” Calling the parent class constructor
me->if_t100_message~t100key = textid. ” Set the error message key
ENDMETHOD.
ENDCLASS.

” Behavior Handler Class for EMP entity
CLASS lhc_EMP DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
” Method to check instance authorization for each operation
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR emp RESULT result.

” Methods for CRUD operations
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE emp.

METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE emp.

METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE emp.

METHODS read FOR READ
IMPORTING keys FOR READ emp RESULT result.

METHODS lock FOR LOCK
IMPORTING keys FOR LOCK emp.
ENDCLASS.

CLASS lhc_EMP IMPLEMENTATION.

METHOD create.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).

LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
DATA ls_employee TYPE zun_emp_tab.

” Map entity fields to employee structure
ls_employee-emp_id = <ls_entity>-EmpId.
ls_employee-first_name = <ls_entity>-FirstName.
ls_employee-last_name = <ls_entity>-LastName.
ls_employee-date_of_birth = <ls_entity>-DateOfBirth.
ls_employee-email = <ls_entity>-Email.
ls_employee-hire_date = <ls_entity>-HireDate.
ls_employee-salary = <ls_entity>-Salary.
ls_employee-curry = <ls_entity>-Curry.

” Add to buffer as create
lo_buffer->add_to_buffer( iv_flag = ‘C’ is_employee = ls_employee ).

” Return mapped keys (required by RAP)
INSERT VALUE #( %cid = <ls_entity>-%cid empID = ls_employee-emp_id ) INTO TABLE mapped-emp.
ENDLOOP.
ENDMETHOD.

METHOD update.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).

LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
” Fetch existing employee from DB to buffer with flag U
DATA ls_db TYPE zun_emp_tab.
SELECT SINGLE * FROM zun_emp_tab WHERE emp_id = @<ls_entity>-EmpId INTO _db.
” Overwrite fields if updated in <ls_entity>
IF <ls_entity>-FirstName IS NOT INITIAL.
ls_db-first_name = <ls_entity>-FirstName.
ENDIF.
IF <ls_entity>-LastName IS NOT INITIAL.
ls_db-last_name = <ls_entity>-LastName.
ENDIF.
IF <ls_entity>-DateOfBirth IS NOT INITIAL.
ls_db-date_of_birth = <ls_entity>-DateOfBirth.
ENDIF.
IF <ls_entity>-email IS NOT INITIAL.
ls_db-email = <ls_entity>-email.
ENDIF.
IF <ls_entity>-HireDate IS NOT INITIAL.
ls_db-hire_date = <ls_entity>-HireDate.
ENDIF.
IF <ls_entity>-salary IS NOT INITIAL.
ls_db-salary = <ls_entity>-salary.
ENDIF.
IF <ls_entity>-curry IS NOT INITIAL.
ls_db-curry = <ls_entity>-curry.
ENDIF.

” Add updated employee to buffer with flag ‘U’
lo_buffer->add_to_buffer( iv_flag = ‘U’ is_employee = ls_db ).

” Return mapped keys
INSERT VALUE #( %cid = <ls_entity>-%cid_ref empID = ls_db-emp_id ) INTO TABLE mapped-emp.
ENDLOOP.
ENDMETHOD.

METHOD delete.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).

LOOP AT keys ASSIGNING FIELD-SYMBOL(<ls_key>).
” Create minimal structure for deletion
DATA ls_employee TYPE zun_emp_tab.
ls_employee-emp_id = <ls_key>-EmpId.

” Add to buffer with flag ‘D’
lo_buffer->add_to_buffer( iv_flag = ‘D’ is_employee = ls_employee ).

” Return mapped keys
INSERT VALUE #( %cid = <ls_key>-%cid_ref empID = <ls_key>-EmpId ) INTO TABLE mapped-emp.
ENDLOOP.
ENDMETHOD.

METHOD read.
” Implement read logic here if required
ENDMETHOD.

METHOD lock.
” Implement lock logic if required
ENDMETHOD.

ENDCLASS.

” Saver class to persist data with validation and proper error handling
CLASS lsc_ZUN_EMP_ROOT IMPLEMENTATION.

METHOD save.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).
LOOP AT lo_buffer->mt_buffer ASSIGNING FIELD-SYMBOL(<ls_buf>).
CASE <ls_buf>-flag.
WHEN ‘C’. ” If the flag is ‘C’, perform Insert operation
INSERT zun_emp_tab FROM <ls_buf>-lv_data.
WHEN ‘U’. ” If the flag is ‘U’, perform Update operation
UPDATE zun_emp_tab FROM <ls_buf>-lv_data.
WHEN ‘D’. ” If the flag is ‘D’, perform Delete operation
DELETE FROM zun_emp_tab WHERE emp_id = <ls_buf>-lv_data-emp_id.
ENDCASE.
ENDLOOP.
CLEAR lo_buffer->mt_buffer. ” Clear the buffer after saving changes
ENDMETHOD.

METHOD finalize.
” Optional post-save logic
ENDMETHOD.

METHOD check_before_save.
” Optional pre-save validations
ENDMETHOD.

METHOD adjust_numbers.
ENDMETHOD.

METHOD cleanup.
” Optional cleanup logic
ENDMETHOD.

METHOD cleanup_finalize.
” Optional final cleanup
ENDMETHOD.

ENDCLASS.

Step 8: Create a Service Definition

We expose the Projection View as a service that can be used by other applications or systems.

@EndUserText.label: ‘Service defination For Projection’
define service ZUN_SRV_DD {
expose zun_emp_proj as EMP;
}

Step 9: Bind the Service to Make it Available

Once we define the service, we create a Service Binding to make the service available for use in the system.

Step 10: Test CRUD Operations

Finally, we test the system by adding, updating, and deleting records. This shows how the system behaves when interacting with employee data.

I am testing a create operation.

 


Successfully created a record. Updating a record that we created.


Successfully updated the record. Now, I am going to delete the updated record.

 


Successfully deleted the record.

Conclusion and Usage

In this blog, we learned how to implement CRUD operations in SAP RAP using an employee management example. We created a database table, set up views, and defined behavior for creating, updating, and deleting employee records.

Why We Use Flags

The flags (C for Create, U for Update, D for Delete) help us track which operation needs to be performed on the data. These flags allow the system to know whether to insert, update, or delete a record in the database.

Using AI for Faster Content Creation

While practicing and writing the code, I used AI for faster content generation. AI helps speed up tasks like documentation and explanations, but the real learning comes from coding and understanding the process firsthand.

 

​  In this blog, I’m going to walk you through how to implement unmanaged CRUD operations in SAP RAP for an on-premise system. We’ll be using a simple employee management example to cover the basics of creating, updating, and deleting employee records.By the end of this post, you’ll understand how to work with CRUD operations in the RAP framework and get hands-on experience with it. I’ve been working on this project recently, and I figured it would be useful to share the process with you.Just a quick note: I’ve been using AI (like GenAI) to help with writing content for this blog. It’s been super helpful for organizing thoughts and getting content down quickly while I focus on the technical stuff. AI’s a great tool for speeding up writing, and I think it’s worth mentioning how it’s making content creation a bit easier for me.Visual Structure Example:+—————————————+
| Step 1: Create Database Table |
+—————————————+
|
V
+—————————————+
| Step 2: Create Root View |
+—————————————+
|
V
+—————————————+
| Step 3: Create Projection View |
+—————————————+
|
V
+—————————————+
| Step 4: Create Behavior Definition |
+—————————————+
|
V
+—————————————+
| Step 5: Create Behavior for Projection|
+—————————————+
|
V
+—————————————+
| Step 6: Create Metadata Extension |
+—————————————+
|
V
+—————————————+
| Step 7: Implement CRUD Logic |
+—————————————+
|
V
+—————————————+
| Step 8: Create Service Definition |
+—————————————+
|
V
+—————————————+
| Step 9: Bind the Service |
+—————————————+
|
V
+—————————————+
| Step 10: Test CRUD Operations |
+—————————————+Step 1: Create a Database TableHere, we create a table in the database that stores employee information like employee ID, name, email, salary, etc. We use special annotations to tell SAP how this table should be used.@EndUserText.label : ‘Employee Table’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zun_emp_tab {
key client : abap.clnt not null;
key emp_id : zempid not null;
first_name : abap.char(30);
last_name : abap.char(30);
date_of_birth : abap.dats;
email : abap.sstring(60);
hire_date : abap.dats;
@Semantics.amount.currencyCode : ‘zun_emp_tab.curry’
salary : abap.curr(15,2);
curry : abap.cuky;
}Step 2: Create a Root View for the TableThe Root View is like a connection between the database table and the system. It allows the data to be used for CRUD operations.@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view’
@Metadata.ignorePropagatedAnnotations: true
define root view entity zun_emp_root as select from zun_emp_tab
{
key emp_id as EmpId,
first_name as FirstName,
last_name as LastName,
date_of_birth as DateOfBirth,
email as Email,
hire_date as HireDate,
@Semantics.amount.currencyCode: ‘curry’
salary as Salary,
curry as Curry
}Step 3: Create a Projection View for the Root ViewA Projection View is a simplified version of the Root View, designed specifically for consumption in applications. It lets users view and edit employee information in a user-friendly format.@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define root view entity zun_emp_proj as projection on zun_emp_root
{
key EmpId,
FirstName,
LastName,
DateOfBirth,
Email,
HireDate,
@Semantics.amount.currencyCode: ‘Curry’
Salary,
Curry
}Step 4: Create Behavior Definition for the Root ViewThis is where we define what can happen to the data (create, update, delete). We set permissions and behaviors for each operation.unmanaged implementation in class zbp_un_emp_root unique;
strict ( 2 );
define behavior for zun_emp_root alias EMP
late numbering
lock master
authorization master ( instance )
//etag master <field_name>
{
create;
update;
delete;
}Step 5: Create Behavior Definition for the Projection ViewSimilar to the Root View, we define behavior for the Projection View, ensuring that data can be created, updated, and deleted in the UI.projection;
strict ( 2 );

define behavior for zun_emp_proj alias EMP
{
use create;
use update;
use delete;
}Step 6: Create a Metadata Extension for the Projection ViewHere, we enhance the UI by adding labels, fields, and other settings so users can easily interact with the employee data.@Metadata.layer: #CUSTOMER

@UI.headerInfo: {
typeName: ‘Employee’,
typeNamePlural: ‘Employees’,
title: {
type: #STANDARD,
label: ‘Employee ID’,
value: ‘EmpId’
},
description: {
label: ‘First Name’,
value: ‘FirstName’
}
}

annotate view zun_emp_proj with {

//=========================
// Facets (sections)
//=========================
.facet: [
{
id: ‘GeneralInfo’,
type: #IDENTIFICATION_REFERENCE,
label: ‘General Information’,
position: 10
}
]

//=========================
// General Information Fields
//=========================
.identification: [{ position: 10, label: ‘Employee ID’ }]
.selectionField: [{ position: 10 }]
.lineItem: [{ position: 10 }]
@EndUserText.label: ‘Employee ID’
EmpId;

.identification: [{ position: 20, label: ‘First Name’ }]
.selectionField: [{ position: 20 }]
.lineItem: [{ position: 20 }]
@EndUserText.label: ‘First Name’
FirstName;

.identification: [{ position: 30, label: ‘Last Name’ }]
.selectionField: [{ position: 30 }]
.lineItem: [{ position: 30 }]
@EndUserText.label: ‘Last Name’
LastName;

.identification: [{ position: 40, label: ‘Date of Birth’ }]
.lineItem: [{ position: 40 }]
.selectionField: [{ position: 40 }]
@EndUserText.label: ‘Date of Birth’
DateOfBirth;

.identification: [{ position: 50, label: ‘Email’ }]
.lineItem: [{ position: 50 }]
@EndUserText.label: ‘Email’
Email;

.identification: [{ position: 60, label: ‘Hire Date’ }]
.selectionField: [{ position: 50 }]
.lineItem: [{ position: 60 }]
@EndUserText.label: ‘Hire Date’
HireDate;

.identification: [{ position: 70, label: ‘Salary’ }]
.lineItem: [{ position: 70 }]
@EndUserText.label: ‘Salary’
Salary;

.identification: [{ position: 80, label: ‘Currency’ }]
.lineItem: [{ position: 80 }]
@EndUserText.label: ‘Currency’
Curry;

};Step 7: Implement the Logic for CRUD OperationsWe write the logic that handles creating, updating, and deleting employee records. We use three key components:Handler Class: This is where the main logic for CRUD operations happens.Saver Class: This class saves the changes to the database.Buffer Class: This is like a temporary holding place for changes before they are saved to the database.Simplified Diagram:+——————+ –> (Create, Update, Delete)
| User Request |
+——————+
|
V
+——————-+ –> (Handler Class) –> +———————+
| Handler Class | ——————–> | Buffer Class |
+——————-+ +———————+
| |
V V
+———————+ +———————+
| Data Saved in DB | <– (Saver Class) <– | Database (Employee Data) |
+———————+ +———————+While practicing, you shouldn’t just copy-paste the code. You should write it yourself to get hands-on experience.” Buffer class to hold create/update/delete entries temporarily
CLASS lcl_buffer DEFINITION CREATE PRIVATE.
PUBLIC SECTION.
TYPES: BEGIN OF ty_buffer,
flag TYPE c LENGTH 1, ” ‘C’ = Create, ‘U’ = Update, ‘D’ = Delete
lv_data TYPE zun_emp_tab, ” The structure that holds employee data
END OF ty_buffer.

CLASS-DATA mt_buffer TYPE STANDARD TABLE OF ty_buffer WITH EMPTY KEY. ” Table to store buffer entries

” Method to get an instance of the buffer class (Singleton pattern)
CLASS-METHODS get_instance
RETURNING VALUE(ro_instance) TYPE REF TO lcl_buffer.

” Method to add records to the buffer (Create, Update, or Delete)
METHODS add_to_buffer
IMPORTING
iv_flag TYPE c ” Flag to specify the type of operation (C/U/D)
is_employee TYPE zun_emp_tab. ” Employee data to be added to the buffer

PRIVATE SECTION.
CLASS-DATA go_instance TYPE REF TO lcl_buffer. ” Holds the single instance of the class
ENDCLASS.

CLASS lcl_buffer IMPLEMENTATION.

METHOD get_instance.
IF go_instance IS NOT BOUND.
go_instance = NEW #( ).
ENDIF.
ro_instance = go_instance.
ENDMETHOD.

METHOD add_to_buffer.
INSERT VALUE #( flag = iv_flag lv_data = is_employee ) INTO TABLE mt_buffer.
ENDMETHOD.

ENDCLASS.

” Custom Exception Class
CLASS zcx_my_exception DEFINITION INHERITING FROM cx_static_check.
PUBLIC SECTION.
INTERFACES if_t100_message. ” This interface is used for handling messages.
METHODS constructor IMPORTING
textid LIKE if_t100_message=>t100key OPTIONAL. ” Constructor to initialize exception with a message
ENDCLASS.

CLASS zcx_my_exception IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor
EXPORTING
previous = previous. ” Calling the parent class constructor
me->if_t100_message~t100key = textid. ” Set the error message key
ENDMETHOD.
ENDCLASS.

” Behavior Handler Class for EMP entity
CLASS lhc_EMP DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
” Method to check instance authorization for each operation
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR emp RESULT result.

” Methods for CRUD operations
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE emp.

METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE emp.

METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE emp.

METHODS read FOR READ
IMPORTING keys FOR READ emp RESULT result.

METHODS lock FOR LOCK
IMPORTING keys FOR LOCK emp.
ENDCLASS.

CLASS lhc_EMP IMPLEMENTATION.

METHOD create.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).

LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
DATA ls_employee TYPE zun_emp_tab.

” Map entity fields to employee structure
ls_employee-emp_id = <ls_entity>-EmpId.
ls_employee-first_name = <ls_entity>-FirstName.
ls_employee-last_name = <ls_entity>-LastName.
ls_employee-date_of_birth = <ls_entity>-DateOfBirth.
ls_employee-email = <ls_entity>-Email.
ls_employee-hire_date = <ls_entity>-HireDate.
ls_employee-salary = <ls_entity>-Salary.
ls_employee-curry = <ls_entity>-Curry.

” Add to buffer as create
lo_buffer->add_to_buffer( iv_flag = ‘C’ is_employee = ls_employee ).

” Return mapped keys (required by RAP)
INSERT VALUE #( %cid = <ls_entity>-%cid empID = ls_employee-emp_id ) INTO TABLE mapped-emp.
ENDLOOP.
ENDMETHOD.

METHOD update.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).

LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
” Fetch existing employee from DB to buffer with flag U
DATA ls_db TYPE zun_emp_tab.
SELECT SINGLE * FROM zun_emp_tab WHERE emp_id = @<ls_entity>-EmpId INTO _db.
” Overwrite fields if updated in <ls_entity>
IF <ls_entity>-FirstName IS NOT INITIAL.
ls_db-first_name = <ls_entity>-FirstName.
ENDIF.
IF <ls_entity>-LastName IS NOT INITIAL.
ls_db-last_name = <ls_entity>-LastName.
ENDIF.
IF <ls_entity>-DateOfBirth IS NOT INITIAL.
ls_db-date_of_birth = <ls_entity>-DateOfBirth.
ENDIF.
IF <ls_entity>-email IS NOT INITIAL.
ls_db-email = <ls_entity>-email.
ENDIF.
IF <ls_entity>-HireDate IS NOT INITIAL.
ls_db-hire_date = <ls_entity>-HireDate.
ENDIF.
IF <ls_entity>-salary IS NOT INITIAL.
ls_db-salary = <ls_entity>-salary.
ENDIF.
IF <ls_entity>-curry IS NOT INITIAL.
ls_db-curry = <ls_entity>-curry.
ENDIF.

” Add updated employee to buffer with flag ‘U’
lo_buffer->add_to_buffer( iv_flag = ‘U’ is_employee = ls_db ).

” Return mapped keys
INSERT VALUE #( %cid = <ls_entity>-%cid_ref empID = ls_db-emp_id ) INTO TABLE mapped-emp.
ENDLOOP.
ENDMETHOD.

METHOD delete.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).

LOOP AT keys ASSIGNING FIELD-SYMBOL(<ls_key>).
” Create minimal structure for deletion
DATA ls_employee TYPE zun_emp_tab.
ls_employee-emp_id = <ls_key>-EmpId.

” Add to buffer with flag ‘D’
lo_buffer->add_to_buffer( iv_flag = ‘D’ is_employee = ls_employee ).

” Return mapped keys
INSERT VALUE #( %cid = <ls_key>-%cid_ref empID = <ls_key>-EmpId ) INTO TABLE mapped-emp.
ENDLOOP.
ENDMETHOD.

METHOD read.
” Implement read logic here if required
ENDMETHOD.

METHOD lock.
” Implement lock logic if required
ENDMETHOD.

ENDCLASS.

” Saver class to persist data with validation and proper error handling
CLASS lsc_ZUN_EMP_ROOT IMPLEMENTATION.

METHOD save.
DATA(lo_buffer) = lcl_buffer=>get_instance( ).
LOOP AT lo_buffer->mt_buffer ASSIGNING FIELD-SYMBOL(<ls_buf>).
CASE <ls_buf>-flag.
WHEN ‘C’. ” If the flag is ‘C’, perform Insert operation
INSERT zun_emp_tab FROM <ls_buf>-lv_data.
WHEN ‘U’. ” If the flag is ‘U’, perform Update operation
UPDATE zun_emp_tab FROM <ls_buf>-lv_data.
WHEN ‘D’. ” If the flag is ‘D’, perform Delete operation
DELETE FROM zun_emp_tab WHERE emp_id = <ls_buf>-lv_data-emp_id.
ENDCASE.
ENDLOOP.
CLEAR lo_buffer->mt_buffer. ” Clear the buffer after saving changes
ENDMETHOD.

METHOD finalize.
” Optional post-save logic
ENDMETHOD.

METHOD check_before_save.
” Optional pre-save validations
ENDMETHOD.

METHOD adjust_numbers.
ENDMETHOD.

METHOD cleanup.
” Optional cleanup logic
ENDMETHOD.

METHOD cleanup_finalize.
” Optional final cleanup
ENDMETHOD.

ENDCLASS.Step 8: Create a Service DefinitionWe expose the Projection View as a service that can be used by other applications or systems.@EndUserText.label: ‘Service defination For Projection’
define service ZUN_SRV_DD {
expose zun_emp_proj as EMP;
}Step 9: Bind the Service to Make it AvailableOnce we define the service, we create a Service Binding to make the service available for use in the system.Step 10: Test CRUD OperationsFinally, we test the system by adding, updating, and deleting records. This shows how the system behaves when interacting with employee data.I am testing a create operation. Successfully created a record. Updating a record that we created.Successfully updated the record. Now, I am going to delete the updated record. Successfully deleted the record.Conclusion and UsageIn this blog, we learned how to implement CRUD operations in SAP RAP using an employee management example. We created a database table, set up views, and defined behavior for creating, updating, and deleting employee records.Why We Use FlagsThe flags (C for Create, U for Update, D for Delete) help us track which operation needs to be performed on the data. These flags allow the system to know whether to insert, update, or delete a record in the database.Using AI for Faster Content CreationWhile practicing and writing the code, I used AI for faster content generation. AI helps speed up tasks like documentation and explanations, but the real learning comes from coding and understanding the process firsthand.   Read More Technology Blog Posts by Members articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author