Local Handler Class
In an unmanaged RAP scenario, the local handler class is where you write the ABAP code to implement the behavior defined in the behavior definition. This includes implementing the standard CRUD (Create, Read, Update, Delete) operations and any custom actions.
Role of the Local Handler Class:
- It acts as the "brain" of your RAP business object, containing the code that interacts with the database and enforces business rules.
- It processes requests from the service layer and performs the necessary actions.
- It handles data manipulation, validation, and authorization.
Keys in Local Handler Class:
- Keys are crucial within the local handler class because they are used to identify specific instances of the business object.
- For example, when updating a customer, the customer_id key is used to locate the correct customer record in the database.
- When creating a new entity (like an attachment), the handler might need to generate a new unique key.
- Key fields are often used in WHERE clauses in database operations to ensure that the correct data is being accessed or modified.
Entities:
- Within the local handler class, the term "entities" refers to the data being processed—typically, a table of instances.
- When creating new customers, the "entities" parameter would hold the data for the new customer records.
- When updating customers, "entities" would contain the modified data for the customers being updated.
- When deleting, "entities" would identify which customer instances to delete.
CRUD Operation Examples:
Create:
- This method handles the creation of new customer records.
- It iterates through the entities to be created.
- It generates a new customer_id (if it's not provided).
- It inserts the new customer data into the zztmfcustomer database table.
- It handles error situations (e.g., if the database insertion fails).
- It returns the created customer IDs with %cid (client ID) to the framework.
Read:
- This method retrieves customer data based on the provided keys.
- It iterates through the keys (which contain the customer_id).
- It selects the customer data from the zztmfcustomer table using the customer_id in the WHERE clause.
- It appends the retrieved data to the result.
- It handles the case where a customer with the given ID is not found.
Update:
- This method updates existing customer records.
- It iterates through the entities containing the updated data.
- It uses the MODIFY statement to update the corresponding record in the zztmfcustomer table, using the customer_id in the WHERE clause to identify the record.
- It handles potential errors during the update.
Delete:
- This method deletes customer records.
- It iterates through the keys (containing the customer_id of the records to be deleted).
- It deletes the records from the zztmfcustomer table using the customer_id in the WHERE clause.
- It includes error handling.
METHODS create FOR MODIFY IMPORTING entities FOR CREATE Customer.
METHODS modify FOR MODIFY IMPORTING entities FOR UPDATE Customer.
METHODS delete FOR MODIFY IMPORTING keys FOR DELETE Customer.
METHODS read FOR READ IMPORTING keys FOR READ Customer RESULT result.ASSOCIATION :
The Associated Child entities should be created only from a Parent Entity, in the above they are specified as Root\_Associated Entity , however the other operations of the class can be handled directly by declaring a method.
METHODS create_ContactMedium FOR MODIFY IMPORTING entities FOR CREATE Customer\_ContactMedium.
METHODS create_CreditProfile FOR MODIFY IMPORTING entities FOR CREATE Customer\_CreditProfile.
METHODS create_EventInput FOR MODIFY IMPORTING entities FOR CREATE Customer\_EventInput.
METHODS create_EventSubscription FOR MODIFY IMPORTING entities FOR CREATE Customer\_EventSubscription.
METHODS create_Characteristic FOR MODIFY IMPORTING entities FOR CREATE Customer\_Characteristic.
METHODS create_PaymentMethod FOR MODIFY IMPORTING entities FOR CREATE Customer\_PaymentMethod.
METHODS create_RelatedParty FOR MODIFY IMPORTING entities FOR CREATE Customer\_RelatedParty.
METHODS create_TimePeriod FOR MODIFY IMPORTING entities FOR CREATE Customer\_TimePeriodCustom Action: copy
The behavior definition allows defining custom actions.
We defined a copy action for the Customer entity.
Why use it?
Efficiency: Quickly create similar records
Consistency: Maintain default values.
User Experience: Convenient for repetitive data entry.
Implementing the copy Action: Add a method in the local handler class to implement the copy logic.
define behavior for ZC_TMF_Customer alias Customer
authorization master ( instance )
draft table ZZTMFCUSTOMER_d
etag master last_changed_at
lock master total etag last_changed_at
early numbering
{
// Root entity
create;
update;
delete;
action copy;Implement the Method logic:
METHOD copy.
DATA: lv_new_id TYPE zztmfcustomer-id,
ls_customer TYPE zztmfcustomer,
lt_accountref TYPE TABLE OF zztmfaccountref,
lt_agreementre TYPE TABLE OF zztmfagreementre,
lt_contactmedium TYPE TABLE OF zztmfcontactme,
lt_creditprofile TYPE TABLE OF zztmfcreditpro,
lt_eventinput TYPE TABLE OF zztmfeventinput,
lt_eventsubscr TYPE TABLE OF zztmfeventsubscr,
lt_characteris TYPE TABLE OF zztmfcharacteris,
lt_paymentme TYPE TABLE OF zztmfpaymentme,
lt_relatedpart TYPE TABLE OF zztmfrelatedpart,
lt_timeperiod TYPE TABLE OF zztmftimeperiod.
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
" 1. Read original customer
SELECT SINGLE * FROM zztmfcustomer WHERE id = @<ls_entity>-customer_id INTO _customer.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
" 2. Get new customer id
SELECT MAX( id ) FROM zztmfcustomer INTO _new_id.
lv_new_id = lv_new_id + 1.
" 3. Insert new customer (copy, but new id)
ls_customer-id = lv_new_id.
INSERT zztmfcustomer FROM _customer.
" 4. Copy AccountRef
SELECT * FROM zztmfaccountref WHERE id = @<ls_entity>-customer_id INTO TABLE _accountref.
LOOP AT lt_accountref ASSIGNING FIELD-SYMBOL(<ls_acc>).
<ls_acc>-id = lv_new_id.
ENDLOOP.
IF lt_accountref IS NOT INITIAL.
INSERT zztmfaccountref FROM TABLE _accountref.
ENDIF.
" 5. Copy AgreementRe
SELECT * FROM zztmfagreementre WHERE id = @<ls_entity>-customer_id INTO TABLE _agreementre.
LOOP AT lt_agreementre ASSIGNING FIELD-SYMBOL(<ls_agr>).
<ls_agr>-id = lv_new_id.
ENDLOOP.
IF lt_agreementre IS NOT INITIAL.
INSERT zztmfagreementre FROM TABLE _agreementre.
ENDIF.
" 6. Copy ContactMedium
SELECT * FROM zztmfcontactme WHERE id = @<ls_entity>-customer_id INTO TABLE _contactmedium.
LOOP AT lt_contactmedium ASSIGNING FIELD-SYMBOL(<ls_con>).
<ls_con>-id = lv_new_id.
ENDLOOP.
IF lt_contactmedium IS NOT INITIAL.
INSERT zztmfcontactme FROM TABLE _contactmedium.
ENDIF.
" 7. Copy CreditProfile
SELECT * FROM zztmfcreditpro WHERE id = @<ls_entity>-customer_id INTO TABLE _creditprofile.
LOOP AT lt_creditprofile ASSIGNING FIELD-SYMBOL(<ls_cred>).
<ls_cred>-id = lv_new_id.
ENDLOOP.
IF lt_creditprofile IS NOT INITIAL.
INSERT zztmfcreditpro FROM TABLE _creditprofile.
ENDIF.
" 8. Copy EventInput
SELECT * FROM zztmfeventinput WHERE id = @<ls_entity>-customer_id INTO TABLE _eventinput.
LOOP AT lt_eventinput ASSIGNING FIELD-SYMBOL(<ls_evi>).
<ls_evi>-id = lv_new_id.
ENDLOOP.
IF lt_eventinput IS NOT INITIAL.
INSERT zztmfeventinput FROM TABLE _eventinput.
ENDIF.
" 9. Copy EventSubscription
SELECT * FROM zztmfeventsubscr WHERE id = @<ls_entity>-customer_id INTO TABLE _eventsubscr.
LOOP AT lt_eventsubscr ASSIGNING FIELD-SYMBOL(<ls_evs>).
<ls_evs>-id = lv_new_id.
ENDLOOP.
IF lt_eventsubscr IS NOT INITIAL.
INSERT zztmfeventsubscr FROM TABLE _eventsubscr.
ENDIF.
" 10. Copy Characteristic
SELECT * FROM zztmfcharacteris WHERE id = @<ls_entity>-customer_id INTO TABLE _characteris.
LOOP AT lt_characteris ASSIGNING FIELD-SYMBOL(<ls_char>).
<ls_char>-id = lv_new_id.
ENDLOOP.
IF lt_characteris IS NOT INITIAL.
INSERT zztmfcharacteris FROM TABLE _characteris.
ENDIF.
" 11. Copy PaymentMethod
SELECT * FROM zztmfpaymentme WHERE id = @<ls_entity>-customer_id INTO TABLE _paymentme.
LOOP AT lt_paymentme ASSIGNING FIELD-SYMBOL(<ls_pay>).
<ls_pay>-id = lv_new_id.
ENDLOOP.
IF lt_paymentme IS NOT INITIAL.
INSERT zztmfpaymentme FROM TABLE _paymentme.
ENDIF.
" 12. Copy RelatedParty
SELECT * FROM zztmfrelatedpart WHERE id = @<ls_entity>-customer_id INTO TABLE _relatedpart.
LOOP AT lt_relatedpart ASSIGNING FIELD-SYMBOL(<ls_rel>).
<ls_rel>-id = lv_new_id.
ENDLOOP.
IF lt_relatedpart IS NOT INITIAL.
INSERT zztmfrelatedpart FROM TABLE _relatedpart.
ENDIF.
" 13. Copy TimePeriod
SELECT * FROM zztmftimeperiod WHERE id = @<ls_entity>-customer_id INTO TABLE _timeperiod.
LOOP AT lt_timeperiod ASSIGNING FIELD-SYMBOL(<ls_tim>).
<ls_tim>-id = lv_new_id.
ENDLOOP.
IF lt_timeperiod IS NOT INITIAL.
INSERT zztmftimeperiod FROM TABLE _timeperiod.
ENDIF.
" 14. Return new key
APPEND VALUE #( %tky = VALUE #( customer_id = lv_new_id ) ) TO mapped-customer.
ENDLOOP.Draft Functionality
Draft functionality enhances the user experience by allowing users to create or modify business objects without immediately saving the changes to the database. This is particularly useful for complex objects or when multiple steps are involved in creating or editing data.
Draft Lifecycle:
- Edit: The user starts editing an existing object or creates a new one, and the data is saved to a draft.
- Activate: The user confirms the changes, and the draft data is saved to the active database table.
- Discard: The user cancels the changes, and the draft data is deleted.
- Resume: The user returns to a previously started draft to continue editing.
Draft Implementation Examples:
Activate:
- This method activates a draft, saving the changes to the active table.
- It reads the draft data from the zztmfcustomer_d (draft table).
- It copies the data to a structure (ls_customer).
- It updates the zztmfcustomer (active table) with the data.
- It deletes the draft record from zztmfcustomer_d.
- It includes error handling for database operations.
Discard:
- This method discards a draft, deleting the draft data.
- It deletes the draft record from the zztmfcustomer_d table.
- It includes error handling.
- Draft functions is handled automatically in the RAP framework, all you need to is create a table like below and specify it in Behaviour Definition.
@EndUserText.label : 'Table to Store Customer details'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zztmfcustomer_d {
key customer_id : char10 not null;
link : char100;
name : char20 not null;
status : char20;
statusreason : char30;
validfor : datab;
last_changed_at : timestampl;
locallastchangedat : timestampl;
"%admin" : include sych_bdl_draft_admin_inc;
}
ATTACHMENT HANDLING in RAP
@EndUserText.label : 'Customer Attachment'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zztmcustatt {
key attach_id : char10 not null;
key customer_id : char10 not null;
file_name : char100 not null;
file_type : char20 not null;
file_content : abap.rawstring(999999);
created_on : timestampl;
last_changed_at : timestampl;
}
METHOD create_Attachment.
DATA: lt_attach TYPE TABLE OF zztmcustatt,
lv_max_id TYPE zztmcustatt-attach_id.
* " Determine next attachment id
*
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
DATA(lt_target) = <ls_entity>-%target.
SELECT MAX( attach_id ) FROM zztmcustatt where customer_id = @<ls_entity>-customer_id INTO _max_id.
IF sy-subrc = 0.
" Convert lv_max_id to a number, increment
lv_max_id = lv_max_id + 1.
ELSE.
lv_max_id = '0000000001'. " initial value, formatted as needed
ENDIF.
LOOP AT lt_target ASSIGNING FIELD-SYMBOL(<ls_target>).
APPEND VALUE #(
attach_id = lv_max_id
customer_id = <ls_entity>-customer_id " Parent key from the Customer
file_name = <ls_target>-FileName
file_type = <ls_target>-FileType
file_content = <ls_target>-Attachment
created_on = sy-datum && sy-uzeit " or use GET TIME STAMP
) TO lt_attach.
" Increment attachment key (format as needed)
lv_max_id = lv_max_id + 1.
ENDLOOP.
ENDLOOP.
IF lt_attach IS NOT INITIAL.
INSERT zztmcustatt FROM TABLE _attach.
" Map created attachments back
LOOP AT lt_attach ASSIGNING FIELD-SYMBOL(<ls_att>).
APPEND VALUE #( %tky = VALUE #( AttachId = <ls_att>-attach_id ) )
TO mapped-Attachment.
ENDLOOP.
ENDIF.
ENDMETHOD.Create a Service Definition and Service Binding to test the application using FIORI ELEMENTS.
Creation of New Record with Draft Functionality & Attachment
- The Records is not Created but its in Draft Status
A new Attachment is uploaded and Created
- The Records is not Created but its in Draft Status
Conclusion
In Part 2, we covered the implementation details of our Customer Management application. We explored the role of the local handler class in processing business logic, implemented draft functionality to enhance the user experience, and enabled attachment handling to manage files.
This two-part series provided a comprehensive guide to building a Customer Management application with unmanaged RAP. By understanding the concepts and examples presented here, you can create your own robust and user-friendly RAP applications. Remember to adapt the code and techniques to the specific requirements of your projects.
With this you can integrate your RAP application with Process Build Automation for Approval. A workflow handler class should be called in the determination of RAP to call the created Workflow.
As of now, SAP BTP Trial has not provided integration part for free, it can be done only in Licensed mode.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.