In this exercise, you reuse existing business logic for flight travel items in your business object. The business object as such remains managed. You only enable unmanaged save for the travel items and replace the managed access to your persistent table with calls to the existing code.
Note
In this exercise, replace ## with your group number.
Solution
| Repository Object Type | Repository Object ID |
|---|
| CDS Behavior Definition (Model) | /LRN/437F_R_TRAVEL |
| ABAP Class | /LRN/BP_437F_R_TRAVEL |
Task 1: Analyze Existing Code
Analyze existing ABAP class /LRN/CL_S4D437_TRITEM.
Steps
Open the source code of ABAP class /LRN/CL_S4D437_TRITEM.
Press Ctrl + Shift + A.
Enter /LRN/CL_S4D437_ as the search string.
Select /LRN/CL_S4D437_TRITEM (Class) from the list and choose OK.
Analyze the public section of the definition part.
Analyze the code between PUBLIC SECTION. and PROTECTED SECTION.
Task 2: Enable Data Access Implementation
Adjust the behavior definition on data model level Z##_R_TRAVEL. For the child entity Z##_R_TravelItem, specify that you want to implement extra coding to be performed during the save sequence. Then make sure that the framework does no longer take care of write access to the persistent table Z##_TRITEM.
Steps
Edit your behavior definition on data model level Z##_R_TRAVEL and locate the define behavior statement for the child entity Z##_R_TravelItem.
For example, you can press Ctrl + F to invoke a search dialog where you search for R_TravelItem.
Specify that you want to implement additional coding to be performed during the save sequence.
Adjust the code as follows:
1234
define behavior for Z##_R_TravelItem alias Item
persistent table z##_tritem
with additional save
draft table z##_tritem_d
Perform a syntax check.
Press Ctrl + F2.
Do not invoke the related quick fix yet. Instead, comment or remove the previous addition and replace it with the addition that specifies that you want to take care of the persistence of flight travels yourself.
Adjust the code as follows:
1234
define behavior for Z##_R_TravelItem alias Item
persistent table z##_tritem
with unmanaged save
draft table z##_tritem_d
Perform another syntax check.
Press Ctrl + F2.
Remove or comment the persistent table addition.
Adjust the code as follows:
123
define behavior for Z##_R_TravelItem alias Item
with unmanaged save
draft table z##_tritem_d
Activate the behavior definition. Then, use a quick fix to generate the required method in the save sequence.
Press Ctrl + F3 to activate the development object.
Place the cursor in the code row that starts with with unmanaged and press Ctrl + 1. Alternatively, choose the warning icon with a light bulb that is displayed on the left-hand side of this code row.
From the list of available quick fixes, choose Add required method save_modified in new local saver class.
Result
The quick fix adds a local class lsc_z##_r_travel to your behavior pool class ZBP_##_R_TRAVEL. The local class inherits from global class CL_ABAP_BEHAVIOR_SAVER and redefines the inherited instance method save_modified.
Analyze the signature of the generated method.
For example, place the cursor on save_modified and press F2 to display the ABAP Element Info for the method.
Task 3: Implement the Data Access
Implement the save_modified method of the saver class. For all three importing parameters in turn, implement a loop over the item component and call the related method of the /LRN/CL_S4D437_TRITEM class. To facilitate data mapping between element names in the business object and field names in the signature of the /LRN/CL_S4D437_TRITEM class, define a field mapping for the structure types and use it in CORRESPONDING expressions.
Steps
In the following, you will create an instance of class /LRN/CL_S4D437_TRITEM that encapsulates access to your database table Z##_TRITEM. However, class /LRN/CL_S4D437_TRITEM and database table Z##_TRITEM belong to different software components, and an object of one software component cannot be used in another software component by default, as software components provide their functionality for other software components via explicitly released APIs.
Therefore, you must first C1 release your database table Z##_TRITEM so that class /LRN/CL_S4D437_TRITEM can access it.
In the Project Explorer, open the context menu for database table Z##_TRITEM.
Choose API State→Add Use System-Internally (Contract C1)....
On the Add Release Contract dialog, choose Next.
In the Validate Changes step, choose Next.
Select a transport request and choose Finish.
In the save_modified method of the saver class, now create an instance of the /LRN/CL_S4D437_TRITEM class and store a reference to the new instance in an inline declared variable (suggested name: model). Supply the importing parameter of the constructor with the name of your database table for travel items Z##_TRITEM.
Adjust the code as follows:
123456
METHOD save_modified.
DATA(model) = NEW /lrn/cl_s4d437_tritem(
i_table_name = 'Z##_TRITEM' ).
ENDMETHOD.
Implement a loop over the item component of the importing parameter delete, using an inline declared field symbol (suggested name: <item_d>).
Adjust the code as follows:
12345678910
METHOD save_modified.
DATA(model) = NEW /lrn/cl_s4d437_tritem(
i_table_name = 'Z##_TRITEM' ).
LOOP AT delete-item ASSIGNING FIELD-SYMBOL(<item_d>).
ENDLOOP.
ENDMETHOD.
For each row, call the delete_item method of your /LRN/CL_S4D437_TRITEM instance. Supply its importing parameter with the uuid of the current row of delete-item.
Adjust the code as follows:
12345678910
METHOD save_modified.
DATA(model) = NEW /lrn/cl_s4d437_tritem(
i_table_name = 'Z##_TRITEM' ).
LOOP AT delete-item ASSIGNING FIELD-SYMBOL(<item_d>).
model->delete_item( i_uuid = <item_d>-itemuuid ).
ENDLOOP.
ENDMETHOD.
Similarly, implement a loop over the item component of the importing parameter create, using an inline declared field symbol (suggested name: <item_c>).
At the end of the method, add the following code:
123
LOOP AT create-item ASSIGNING FIELD-SYMBOL(<item_c>).
ENDLOOP.
For each row, call the create_item method of your /LRN/CL_S4D437_TRITEM instance. Supply its importing parameter with the data from the current row of create-item. Use a CORRESPONDING expression to convert the row of create-item to the type of input parameter i_item, that is, to structure type /LRN/437_S_TRITEM.
Note
At the moment, the CORRESPONDING expression will only assign the components with identical names in /LRN/437_S_TRITEM and in the row type of create-item. That is not the case for most of the components. We use an explicit field mapping in the next step.
Adjust the code as follows:
1234
LOOP AT create-item ASSIGNING FIELD-SYMBOL(<item_c>).
model->create_item(
i_item = CORRESPONDING #( <item_c> ) ).
ENDLOOP.
Edit the behavior definition on data model level Z##_R_TRAVEL. Define a field mapping for structure type /LRN/437_S_TRITEM.
Hint
Structure type /LRN/437_S_TRITEM and persistent table Z##_TRITEM use the same field names. To save time, you can copy from the field mapping for persistent table Z##_TRITEM.
Add the following code to the behavior definition for the child entity Z##_R_TravelItem:
123456789101112131415
mapping for /lrn/437_s_tritem corresponding
{
ItemUuid = item_uuid;
AgencyId = agency_id;
TravelId = travel_id;
CarrierId = carrier_id;
ConnectionId = connection_id;
FlightDate = flight_date;
BookingId = booking_id;
PassengerFirstName = passenger_first_name;
PassengerLastName = passenger_last_name;
ChangedAt = changed_at;
ChangedBy = changed_by;
LocChangedAt = loc_changed_at;
}
Return to the implementation of the save_modified method. Adjust the CORRESPONDING expression so that it uses the field mapping for structure type /LRN/437_S_TRITEM from the behavior definition.
Adjust the code as follows:
12
model->create_item(
i_item = CORRESPONDING #( <item_c> MAPPING FROM ENTITY ) ).
Finally, implement a loop over the item component of the importing parameter update, using an inline declared field symbol (suggested name: <item_u>). For each row, call the update_item method of your /LRN/CL_S4D437_TRITEM instance.
At the end of the method, add the following code:
12345
LOOP AT update-item ASSIGNING FIELD-SYMBOL(<item_u>).
model->update_item(
i_item =
i_itemx = ).
ENDLOOP.
Supply the importing parameter i_item with the data from the current row of update-item. Use the field mapping from the behavior definition as before. Supply importing parameter i_itemx in the same way. But this time, use the addition USING CONTROL to make sure the information is extracted from sub component %control.
Adjust the code as follows:
123456
LOOP AT update-item ASSIGNING FIELD-SYMBOL(<item_u>).
model->update_item(
i_item = CORRESPONDING #( <item_u> MAPPING FROM ENTITY )
i_itemx = CORRESPONDING #( <item_u> MAPPING FROM ENTITY
USING CONTROL ) ).
ENDLOOP.
Return to the behavior definition and extend the field mapping for structure type /LRN/437_S_TRITEM. Specify that the structure type /LRN/437_S_TRITEMX is the related control structure, then activate the behavior definition and the behavior implementation.
Adjust the code as follows:
123
mapping for /lrn/437_s_tritem
control /lrn/437_s_tritemx corresponding
{
In the behavior definition, press Ctrl + F3 to activate the development object.
In the behavior implementation, press Ctrl + F3 to activate the development object.
Test the preview for the OData UI service. Make sure that you can successfully create, update and delete flight travel items.
Open the service binding, place the cursor on the root entity and choose Preview....
In the preview, display the details for one of the travels.
Choose Edit to change to edit mode.
Ensure that you can successfully create new travel items via the UI. Also make sure that you can update and delete existing travel items.
Use the preview tool in Eclipse to check whether the contents of database table Z##_TRITEM have been updated accordingly.
Task 4: Optional: Handle the Messages
Handle the returning parameters of the delete_item, create_item, and update_item methods of class /LRN/CL_S4D437_TRITEM. Store the returned messages in the reported parameter of the save_modified method.
Note
Because all returning parameters have the same type, it is a good idea to do the required mapping in a private helper method of the saver class.
Steps
In the saver class, define a new private instance method (suggested name: map_message). Define an importing parameter of structure type SYMSG (suggested name: i_msg) and a returning parameter of type REF TO if_abap_behv_message (suggested name: r_msg).
Adjust the code as follows:
1234567891011121314
CLASS lsc_z##_r_travel DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS save_modified REDEFINITION.
PRIVATE SECTION.
METHODS
map_message
IMPORTING
i_msg TYPE symsg
RETURNING
VALUE(r_msg) TYPE REF TO if_abap_behv_message.
ENDCLASS.
Use a quick fix to generate the implementation for the method.
Choose the error icon with a light bulb next to the code row with the method name to display the quick assist proposals.
From the list of available quick fixes, choose Add implementation for map_message.
Implement the method. First, map the message types in component msgty of parameter i_msg to a local variable of type if_abap_behv_message=>t_severity (suggested name: severity).
Hint
As values for the local variable, use the components of the constant structure if_abap_behv_message=>severity.
You can either use a SWITCH expression or a more old-fashioned CASE … ENDCASE structure.
In the implementation of method map_message, add the following code:
123456
DATA(severity) = SWITCH #( i_msg-msgty
WHEN 'S' THEN if_abap_behv_message=>severity-success
WHEN 'I' THEN if_abap_behv_message=>severity-information
WHEN 'W' THEN if_abap_behv_message=>severity-warning
WHEN 'E' THEN if_abap_behv_message=>severity-error
ELSE if_abap_behv_message=>severity-none ).
Alternative solution:
12345678910111213
DATA severity TYPE if_abap_behv_message=>t_severity.
CASE i_msg-msgty.
WHEN 'S'.
severity = if_abap_behv_message=>severity-success.
WHEN 'I'.
severity = if_abap_behv_message=>severity-information.
WHEN 'W'.
severity = if_abap_behv_message=>severity-warning.
WHEN 'E'.
severity = if_abap_behv_message=>severity-error.
WHEN OTHERS.
severity = if_abap_behv_message=>severity-none.
ENDCASE.
Call the inherited functional method new_message and assign the result to the returning parameter r_msg. Supply the importing parameters with the related components of parameter i_msg, except for parameter severity which you supply with your local variable severity.
At the end of the method map_message, add the following code:
12345678
r_msg = new_message(
id = i_msg-msgid
number = i_msg-msgno
severity = severity
v1 = i_msg-msgv1
v2 = i_msg-msgv2
v3 = i_msg-msgv3
v4 = i_msg-msgv4 ).
Return to the implementation of the save_modified method. Find the call of the delete_item method and store the result in an inline declared variable (suggested name: msg_d).
Adjust the code as follows:
1
DATA(msg_d) = model->delete_item( i_uuid = <item_d>-itemuuid ).
If the result is not initial, append a new row to the item component of the reported parameter. Fill the %tky-itemuuid component with the uuid of the current flight travel item and component %msg via a call of the private method that you just implemented.
Adjust the code as follows:
123456
DATA(msg_d) = model->delete_item( i_uuid = <item_d>-itemuuid ).
IF msg_d IS NOT INITIAL.
APPEND VALUE #( %tky-itemuuid = <item_d>-itemuuid
%msg = map_message( msg_d ) )
TO reported-item.
ENDIF.
Adjust the call of create_item accordingly.
Adjust the code as follows:
1234567
DATA(msg_c) = model->create_item(
i_item = CORRESPONDING #( <item_c> MAPPING FROM ENTITY ) ).
IF msg_c IS NOT INITIAL.
APPEND VALUE #( %tky-itemuuid = <item_c>-itemuuid
%msg = map_message( msg_c ) )
TO reported-item.
ENDIF.
Finally, adjust the call of update_item.
Adjust the code as follows:
123456789
DATA(msg_u) = model->update_item(
i_item = CORRESPONDING #( <item_u> MAPPING FROM ENTITY )
i_itemx = CORRESPONDING #( <item_u> MAPPING FROM ENTITY
USING CONTROL ) ).
IF msg_u IS NOT INITIAL.
APPEND VALUE #( %tky-itemuuid = <item_u>-itemuuid
%msg = map_message( msg_u ) )
TO reported-item.
ENDIF.
Activate the ABAP class.
Press Ctrl + F3 to activate the development object.
Retest the preview for the OData UI service. Ensure that the messages returned by the delete_item, create_item, and update_item methods of class /LRN/CL_S4D437_TRITEM are displayed on the UI.
Open the service binding, place the cursor on the root entity and choose Preview....
In the preview, display the details for one of the travels.
Choose Edit to change to edit mode.
Make sure that a corresponding success message is displayed when you have successfully created a new travel item.
Also, make sure that appropriate messages are displayed when updating and deleting existing travel items.