Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
vinu_Kurian
Active Participant
In this blog lets look at the Managed Scenario (Behavior Implementation )  in the ABAP on BTP platform .

 

As mentioned in the title , Managed scenario helps to eliminate most of the code (used for CRUD operations in the Implementation class).  Since the managed approach takes all the responsibilities  of the CRUD operations , we just need to take account of certain authorizations (If we are going to implement the authorization objects and related objects ).

 

Lets consider the following scenario :

We have a student portal application with one header table and two other child tables .

Student Header Table :
@EndUserText.label : 'Header  for Student'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table ystudent_hdr {
key client : abap.clnt not null;
key sid : sysuuid_x16 not null;
admission_no : abap.char(10);
fname : abap.char(25);
mname : abap.char(25);
lname : abap.char(25);
contact_no1 : abap.char(10);
contact_no2 : abap.char(10);
dob : abap.dats;
gender : ydgender;
semail : abap.char(50);
pemail : abap.char(50);
paddress : abap.string(256);
caddress : abap.string(256);
blood_group : ydbg;
height : abap.dec(4,4);
weight : abap.dec(4,4);

}

Student Academic details:
@EndUserText.label : 'Current Academic Details'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table yst_cracademic {
key client : abap.clnt not null;
@AbapCatalog.foreignKey.screenCheck : false
key sid : sysuuid_x16 not null
with foreign key ystudent_hdr
where client = yst_cracademic.client
and sid = yst_cracademic.sid;
key course : ydcourse not null;
key semester : ydsemester not null;
status : ydsemstat;
percentage : abap.dec(3,2);
feedback : abap.string(256);

}

Student attendance details :
@EndUserText.label : 'Semester Attendance'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table yst_attendance {
key client : abap.clnt not null;
@AbapCatalog.foreignKey.screenCheck : false
key sid : sysuuid_x16 not null
with foreign key ystudent_hdr
where client = yst_attendance.client
and sid = yst_attendance.sid;
key course : ydcourse not null;
key semester : ydsemester not null;
status : ydsemstat;
percentage : abap.dec(3,2);
feedback : abap.string(256);

}

Following CDS entities representing the Parent child Hierarchy :

Header :
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Student Header'
@Metadata.allowExtensions: true
define root view entity YSTUDENT_HDR_I
as select from ystudent_hdr
composition [0..*] of YST_CRACADEMIC_I as _academic
composition [0..*] of YST_ATTENDANCE_I as _attendance
association to YI_GENDER as _gender on $projection.gender = _gender.Value
association to YI_BG as _bg on $projection.blood_group = _bg.Value
{
key sid,
admission_no,
fname,
mname,
lname,
contact_no1,
contact_no2,
dob,
gender,
_gender.Description as genderdesc,
semail,
pemail,
paddress,
caddress,
blood_group,
_bg.Description as bg_desc,
height,
weight,
_academic,
_attendance,
_gender,
_bg
// _association_name // Make association public
}

Metadata Extension :
@Metadata.layer: #CORE
@UI: {
headerInfo: { typeName: 'Student Detail',
typeNamePlural: 'Student Details',

title: { type: #STANDARD, label: 'Student Details', value: 'fname' },
description:{ type: #STANDARD , label: 'Student Details' , value : 'lname'}

},
presentationVariant: [{ sortOrder: [{by: 'fname', direction: #ASC}] }]


}
@Search.searchable: true
annotate view YSTUDENT_HDR_I with
{
@UI.facet: [{ id: 'Student',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Student Details',
position: 10
},
{ id: 'Academic',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Academic Details',
position: 20,
targetElement: '_academic'},
{ id: 'Attendance',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Attendance Details',
position: 20,
targetElement: '_attendance'}]

@UI: { identification: [{ position: 10, label: 'Student ID' }] }
@UI.hidden: true
sid;
@UI: { lineItem: [{ position: 20, importance: #HIGH, label: 'Admission Number' }],
identification: [{ position: 20, label: 'Admission Number' }] }
@Search.defaultSearchElement: true
admission_no;
@UI: { lineItem: [{ position: 30, importance: #HIGH, label: 'First Name' }],
identification: [{ position: 30, label: 'First Name' }] }
@Search.defaultSearchElement: true
fname;
@UI: { lineItem: [{ position: 40, importance: #HIGH, label: 'Middle Name' }],
identification: [{ position: 40, label: 'Middle Name' }] }
mname;
@UI: { lineItem: [{ position: 50, importance: #HIGH, label: 'Last Name' }],
identification: [{ position: 50, label: 'Last Name' }] }
@Search.defaultSearchElement: true
lname;
@UI: { lineItem: [{ position: 60, importance: #HIGH, label: 'Contact Number 1' }],
identification: [{ position: 60, label: 'Contact Number 1' }] }
contact_no1;
@UI: { lineItem: [{ position: 70, importance: #HIGH, label: 'Contact Number 2' }],
identification: [{ position: 70, label: 'Contact Number 2' }] }
contact_no2;
@UI: { lineItem: [{ position: 80, importance: #HIGH, label: 'Date of Birth' }],
identification: [{ position: 80, label: 'Date of Birth' }] }
dob;
@UI: { lineItem: [{ position: 90, importance: #HIGH, label: 'Gender' }],
identification: [{ position: 90, label: 'Gender' }] }
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_GENDER' , element: 'Value' },
additionalBinding: [{ localElement: 'genderdesc', element: 'Description' }]
}]
gender;
@UI: { lineItem: [{ position: 100, importance: #HIGH, label: '' }],
identification: [{ position: 100, label: '' }] }
genderdesc;
@UI: { lineItem: [{ position: 110, importance: #HIGH, label: 'Student Email' }],
identification: [{ position: 110, label: 'Student Email' }] }
semail;
@UI: { lineItem: [{ position: 120, importance: #HIGH, label: 'Parent Email' }],
identification: [{ position: 120, label: 'Parent Email' }] }
pemail;
@UI: { lineItem: [{ position: 130, importance: #HIGH, label: 'Parent Address' }],
identification: [{ position: 130, label: 'Parent Address' }] }
paddress;
@UI: { lineItem: [{ position: 140, importance: #HIGH, label: 'Student Address ' }],
identification: [{ position: 140, label: 'Student Address ' }] }
caddress;
@UI: { lineItem: [{ position: 150, importance: #HIGH, label: 'Blood Group' }],
identification: [{ position: 150, label: 'Blood Group' }] }
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_BG' , element: 'Value' },
additionalBinding: [{ localElement: 'bg_desc', element: 'Description' }]
}]
blood_group;
@UI: { lineItem: [{ position: 160, importance: #HIGH, label: '' }],
identification: [{ position: 160, label: '' }] }
bg_desc;
@UI: { lineItem: [{ position: 170, importance: #HIGH, label: 'Height in CM' }],
identification: [{ position: 170, label: 'Height in CM' }] }
height;
@UI: { lineItem: [{ position: 180, importance: #HIGH, label: 'Weight in KG' }],
identification: [{ position: 180, label: 'Weight in KG' }] }
weight;

}

Academic details :
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Academic Details'
@Metadata.allowExtensions: true
define view entity YST_CRACADEMIC_I
as select from yst_cracademic
association to parent YSTUDENT_HDR_I as _HDR on $projection.sid = _HDR.sid
association to YI_COURSE as _course on $projection.course = _course.Value
association to YI_SEMESTER as _semester on $projection.semester = _semester.Value
association to YI_SEMSTAT as _stat on $projection.status = _stat.Value
{
key sid,
key course,
key semester,
_course.Description as course_desc,
_semester.Description as semester_desc,
status,
_stat.Description as semester_status,
percentage,
feedback,
_HDR // Make association public
}

Metadata extension:
@Metadata.layer: #CORE

@UI: {
headerInfo: { typeName: 'Academic Detail',
typeNamePlural: 'Academic Details',

title: { type: #STANDARD, label: 'Academic Details', value: 'course' },
description:{ type: #STANDARD , label: 'Academic Details' , value : 'course_desc'}

},
presentationVariant: [{ sortOrder: [{by: 'semester', direction: #ASC}] }]


}
@Search.searchable: true
annotate view YST_CRACADEMIC_I with
{
@UI.facet: [{ id: 'Acadmic',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Academic Details',
position: 10
}]
@UI: { identification: [{ position: 10, label: 'Student ID' }] }
@UI.hidden: true
sid;
@UI: { lineItem: [{ position: 20, importance: #HIGH, label: 'Course' }],
identification: [{ position: 20, label: 'Course' }] }
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_COURSE' , element: 'Value' },
additionalBinding: [{ localElement: 'course_desc', element: 'Description' }]
}]
course;
@UI: { lineItem: [{ position: 30, importance: #HIGH, label: '' }],
identification: [{ position: 30, label: '' }] }
@Search.defaultSearchElement: true
course_desc;
@UI: { lineItem: [{ position: 40, importance: #HIGH, label: 'Semester' }],
identification: [{ position: 40, label: 'Semester' }] }
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_SEMESTER' , element: 'Value' },
additionalBinding: [{ localElement: 'semester_desc', element: 'Description' }]
}]
semester;
@UI: { lineItem: [{ position: 50, importance: #HIGH, label: '' }],
identification: [{ position: 50, label: '' }] }
@Search.defaultSearchElement: true
semester_desc;
@UI: { lineItem: [{ position: 60, importance: #HIGH, label: 'Status' }],
identification: [{ position: 60, label: 'Status' }] }
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_SEMSTAT' , element: 'Value' },
additionalBinding: [{ localElement: 'semester_status', element: 'Description' }]
}]
status;
@UI: { lineItem: [{ position: 70, importance: #HIGH, label: '' }],
identification: [{ position: 70, label: '' }] }
@Search.defaultSearchElement: true
semester_status;
@UI: { lineItem: [{ position: 80, importance: #HIGH, label: 'Percentage Scored' }],
identification: [{ position: 80, label: 'Percentage Scored' }] }
@Search.defaultSearchElement: true
percentage;
@UI: { lineItem: [{ position: 90, importance: #HIGH, label: 'Student Feed Back' }],
identification: [{ position: 90, label: 'Student Feed Back' }] }
@Search.defaultSearchElement: true
feedback;

}

Attendance Details :
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Attendance'
@Metadata.allowExtensions: true
define view entity YST_ATTENDANCE_I
as select from yst_attendance
association to parent YSTUDENT_HDR_I as _hdr on $projection.sid = _hdr.sid
association to YI_COURSE as _course on $projection.course = _course.Value
association to YI_SEMESTER as _semester on $projection.semester = _semester.Value
association to YI_SEMSTAT as _stat on $projection.status = _stat.Value
{
key sid,
key course,
key semester,
_course.Description as course_desc,
_semester.Description as semester_desc,
status,
_stat.Description as semester_status,
percentage,
feedback,
_hdr // Make association public
}

Metadata Extension :
@Metadata.layer: #CORE
@UI: {
headerInfo: { typeName: 'Attendance Detail',
typeNamePlural: 'Attendance Details',

title: { type: #STANDARD, label: 'Attendance Detail', value: 'course' },
description:{ type: #STANDARD , label: 'Attendance Details' , value : 'course_desc'}

},
presentationVariant: [{ sortOrder: [{by: 'semester', direction: #ASC}] }]


}
@Search.searchable: true
annotate view YST_ATTENDANCE_I
with
{
@UI.facet: [{ id: 'Attendance',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Attendance Details',
position: 10
}]
@UI: { identification: [{ position: 10, label: 'Student ID' }] }
@UI.hidden: true
sid;
@UI: { lineItem: [{ position: 20, importance: #HIGH, label: 'Course' }],
identification: [{ position: 20, label: 'Course' }] }
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_COURSE' , element: 'Value' },
additionalBinding: [{ localElement: 'course_desc', element: 'Description' }]
}]
course;
@UI: { lineItem: [{ position: 30, importance: #HIGH, label: '' }],
identification: [{ position: 30, label: '' }] }
@Search.defaultSearchElement: true
course_desc;
@UI: { lineItem: [{ position: 40, importance: #HIGH, label: 'Semester' }],
identification: [{ position: 40, label: 'Semester' }] }
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_SEMESTER' , element: 'Value' },
additionalBinding: [{ localElement: 'semester_desc', element: 'Description' }]
}]
semester;
@UI: { lineItem: [{ position: 50, importance: #HIGH, label: '' }],
identification: [{ position: 50, label: '' }] }
@Search.defaultSearchElement: true
semester_desc;
@UI: { lineItem: [{ position: 60, importance: #HIGH, label: 'Status' }],
identification: [{ position: 60, label: 'Status' }] }
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity:
{name: 'YI_SEMSTAT' , element: 'Value' },
additionalBinding: [{ localElement: 'semester_status', element: 'Description' }]
}]
status;
@UI: { lineItem: [{ position: 70, importance: #HIGH, label: '' }],
identification: [{ position: 70, label: '' }] }
@Search.defaultSearchElement: true
semester_status;
@UI: { lineItem: [{ position: 80, importance: #HIGH, label: 'Percentage Scored' }],
identification: [{ position: 80, label: 'Percentage Scored' }] }
@Search.defaultSearchElement: true
percentage;
@UI: { lineItem: [{ position: 90, importance: #HIGH, label: 'Student Feed Back' }],
identification: [{ position: 90, label: 'Student Feed Back' }] }
@Search.defaultSearchElement: true
feedback;

}

 

Few other CDS which is used for Search Help :

Blood Group:
@AbapCatalog.sqlViewName: 'YIBG'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Gender'
define view YI_BG as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YBG' )
{
key domain_name,
key value_position,
@Semantics.language: true
key language,
value_low as Value,
@Semantics.text: true
text as Description

}

Domain :


Course :
@AbapCatalog.sqlViewName: 'YICOURSE'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Course'
define view YI_COURSE
as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YCOURSE' )
{
key domain_name,
key value_position,
@Semantics.language: true
key language,
value_low as Value,
@Semantics.text: true
text as Description

}

Domain :


Gender :
@AbapCatalog.sqlViewName: 'YGEN'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Gender'
define view YI_GENDER as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YGENDER' )
{
key domain_name,
key value_position,
@Semantics.language: true
key language,
value_low as Value,
@Semantics.text: true
text as Description

}

Domain :


Semester:
@AbapCatalog.sqlViewName: 'YISEM'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Semester'
define view YI_SEMESTER
as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YSEMESTER' )
{
key domain_name,
key value_position,
@Semantics.language: true
key language,
value_low as Value,
@Semantics.text: true
text as Description

}

Domain :


Status :
@AbapCatalog.sqlViewName: 'YISTAT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Status'
define view YI_SEMSTAT
as select from DDCDS_CUSTOMER_DOMAIN_VALUE_T( p_domain_name: 'YSEMSTAT' )
{
key domain_name,
key value_position,
@Semantics.language: true
key language,
value_low as Value,
@Semantics.text: true
text as Description

}

Domain :


 

Behavior definition :
managed implementation in class YST_BEHAVIOUR unique;
strict;
define behavior for YSTUDENT_HDR_I
persistent table ystudent_hdr
lock master
authorization master ( instance )

{
field ( numbering : managed, readonly ) sid;
create;
update;
delete;
field ( readonly ) genderdesc;
field ( readonly ) bg_desc;
association _attendance { create; }
association _academic { create; }
}

define behavior for YST_ATTENDANCE_I
persistent table yst_attendance
lock dependent by _hdr
authorization dependent by _hdr

{
update;
delete;
field ( readonly ) sid;
field ( readonly ) course_desc;
field ( readonly ) semester_desc;
field ( readonly ) semester_status;
association _hdr;
}

define behavior for YST_CRACADEMIC_I
persistent table yst_cracademic
lock dependent by _HDR
authorization dependent by _HDR

{
update;
delete;
field ( readonly ) sid;
field ( readonly ) course_desc;
field ( readonly ) semester_desc;
field ( readonly ) semester_status;
association _HDR;
}

Behavior Implementation :
****Global Class ************
CLASS yst_behaviour DEFINITION
PUBLIC
abstract
final
for behavior of YSTUDENT_HDR_I .

PUBLIC SECTION.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.



CLASS yst_behaviour IMPLEMENTATION.
ENDCLASS.

****Local Types******

CLASS YST_behaviour2 DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.

METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR ystudent_hdr_i RESULT result.


ENDCLASS.

CLASS YST_behaviour2 IMPLEMENTATION.
METHOD get_instance_authorizations.
********Your code goes here
ENDMETHOD.
ENDCLASS.

 

If we look at the Behavior class over here we have barely written 28 lines of code , if we expose the CDS in a service Definition and create a service Binding , All the CRUD operations for both parent and child works fine . All the CRUD operation code is taken care by the system and we have a minimum effort .

Since SAP recommends using the View Entities in CDS we had to create the class , if we were using just the views the class is optional.

Lets Have a look At the Screen:



NB: The blog is written based on my Research and developments on BTP , If I have mentioned any miss information , Please correct me in the comments .
5 Comments
Abap2021
Newcomer
Hi Vinu,

it seems the table 'yst_attendance' is missing in your tutorial.

KR Chiwing
vinu_Kurian
Active Participant
0 Kudos
Hi Chiwing ,

Thanks for pointing the Mistake , Corrected it 🙂
Prasenjitsbist
Participant
0 Kudos

RAP Managed Scenario is not a Low Code or No Code version This blog will create a wrong information for many people looking for low code/ no code vs ABAP solutions.

 

This solution is available on SAP TechEd videos on YouTube as well incase you need more details. All the best with your RAP Learning.

 

PSB

vinu_Kurian
Active Participant
0 Kudos
There was something missing in the title , corrected it :D. Thanks for pointing this .
tjarliman
Explorer
0 Kudos
Hi vinu_kurian ,

I managed to create similar apps like this where 1 root has more than 1 navigation properties. In your case, 1 student has 1 academis details and 1 attendant details.

During previewing the services via ADT, the apps seems well displayed on the screen like yours (I am pointing to the create buttons where they are correcly displayed). Mine also can display the create buttons perfectly.

But the issue I am having now, is during creation of the Fiori Elements apps using BAS or VSC. where only one "create" button is appearing.

Did you have a chance to generate fiori elements apps based on the service you created above ? and have similar issue with me? if you dont have similar issue, can you let me know how you do it?

Thanks

TJ

 

 
Labels in this area