CRM and CX Blogs by Members
Find insights on SAP customer relationship management and customer experience products in blog posts from community members. Post your own perspective today!
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member


In MVC architecture, model unit is responsible for data retention and is independent of the layout and program control units. Business Object Layer (BOL) together with the Generic Interaction Layer (GenIL) is an essential part of the web client architecture because it is responsible for the data management of the user interface components. The BOL is a standard interface to access an object model that consists of a defined quantity of GenIL components and their objects.

 

In this blog I am going to show the steps to create a custom GenIL model.

 

We have a custom table ZBOL_EMPL_MASTER containing the employee details. Here is the structure:



Our object model will be based on this database table. To create the Object model we need to perform the following steps:

Step 1: Go to transaction SM34 and maintain the view CRMVC_GIL_APPDEF



     a) Double click on Component Definition and click on New Entries to define the custom component(say Z_EMPL). Maintain an implementation class,say ZCL_GENIL_EMPLOYEE



     b) Double click on Component Set Definition and click on New Entries to define the custom component set(say ZSET_EMPL)



     c) Assign the component to the component set



Step 2: Create the following database structures and table types









Step 3: Go to transaction GENIL_MODEL_EDITOR to create the Object model. Give component name as Z_EMPL and click on Change

     a) Right Click on Root Object and select “Create Root Object”, give an object name and maintain the basic settings as shown below





     b) Right click on Dynamic Query Objects and select “Create Dynamic Query Object”. Maintain the object name and the basic settings as shown below





Step 4: Create a custom class (ZCL_EMPL_MASTER_API) to hold the API methods to retrieve data from database. Create two public static methods SEARCH_EMPLOYEE and READ_EMPLOYEE with the following parameters



SEARCH_EMPLOYEE gets the employee keys from the database. IV_STRING contains the where conditions based on which the database query is executed.

 



READ_EMPLOYEE accepts the employee key as input and returns employee attributes for the corresponding employee.

 



Add the following code:

*************************************************************************************************

method search_employee.
refresh et_results.
if iv_string is not initial.
select employee_id
from zbol_empl_master
up to iv_max_hits rows
into corresponding fields of table et_results
where (iv_string).
else.
select employee_id
from zbol_empl_master
up to iv_max_hits rows
into corresponding fields of table et_results.
endif.
endmethod.


*************************************************************************************************

method read_employee.
select single * from zbol_empl_master into corresponding fields of es_empl_att
where employee_id eq is_empl_key-employee_id.
endmethod.


*************************************************************************************************

You can take any other approach to read the table data, like using FMs.

 

Step 5: Go to transaction SE24 and create the custom class ZCL_GENIL_EMPLOYEE which was mentioned during component definition

·         Maintain CL_WCF_GENIL_ABSTR_COMPONENT as the superclass



·         Redefine the method IF_GENIL_APPL_INTLAY~GET_DYNAMIC_QUERY_RESULT. Add the following code


*************************************************************************************************

method if_genil_appl_intlay~get_dynamic_query_result.
data: lr_msg_cont type ref to cl_crm_genil_global_mess_cont,
lv_num_hits type i,
lt_results type zbol_empl_master_key_tab,
lv_max_hits type char5,
lv_max_hits_tmp type int4,
lr_root_object type ref to if_genil_cont_root_object,
lt_request_obj type crmt_request_obj_tab.
field-symbols: <fs_results> type zbol_empl_master_key.
* Retrieve the message container to log eventual messages
lr_msg_cont = iv_root_list->get_global_message_container( ).
* When the max hits is set to 0.
if is_query_parameters-max_hits is initial.
lv_max_hits_tmp = 100. "100 when no max_hits is set
else.
lv_max_hits_tmp = is_query_parameters-max_hits.
endif.
* select the rigth query
case iv_query_name.
when 'SearchEmployee'.
* Call the API and get the result.

call method search_employee
exporting
it_search_criteria = it_selection_parameters
iv_max_hits        = lv_max_hits_tmp
importing
et_results         = lt_results.

if lt_results is not initial.
* Log a message if search result exceed the max hit limit
describe table lt_results lines lv_num_hits.
if lv_num_hits > lv_max_hits_tmp.
lv_max_hits = lv_max_hits_tmp.
lr_msg_cont->add_message( iv_msg_type = 'I'
iv_msg_id = 'ZBOL_MSG'
iv_msg_number = '000'
iv_msg_v1 = lv_max_hits
iv_show_only_once = abap_true ).
endif.
* Loop through the results to build search result objects
loop at lt_results assigning <fs_results>.
try.
* Try to create a new result object
lr_root_object = iv_root_list->add_object(
iv_object_name = 'EMPLOYEE'
is_object_key = <fs_results> ).
* Flag it as direct query result
lr_root_object->set_query_root( abap_true ).
catch cx_crm_genil_duplicate_rel cx_crm_genil_model_error.
* Since the given object name is correct this could not happen!
endtry.
endloop.
* Note: The request object restricts the attributes to read.
* If there is no request object entry or the attributes
* table is empty all attributes are requested.
* read the attributes and relation using the GET_OBJECTS
me->if_genil_appl_intlay~get_objects( it_request_objects = lt_request_obj
iv_root_list = iv_root_list ).
else.
lr_msg_cont->add_message( iv_msg_type = 'W'
iv_msg_id = 'ZBOL_MSG'
iv_msg_number = '001'
iv_show_only_once = abap_true ).
endif.
when others.
return.
endcase.
endmethod.


*************************************************************************************************

·         Redefine the method IF_GENIL_APPL_INTLAY~GET_OBJECTS


*************************************************************************************************

method if_genil_appl_intlay~get_objects.
data lv_root type ref to if_genil_cont_root_object.
data lv_empl_key type zbol_empl_master_key.
data lv_empl_att type zbol_empl_master_attr.
data lv_temp_att type zbol_empl_master_attr.
lv_root = iv_root_list->get_first( ).
while lv_root is bound.
lv_root->get_key( importing es_key = lv_empl_key ).
* Check if attributes should be read
if lv_root->check_attr_requested( ) = abap_true.
zcl_empl_master_api=>read_employee(
exporting is_empl_key = lv_empl_key
importing es_empl_att = lv_empl_att ).
* Return the object only if it still exists
if lv_empl_att is not initial.
* Put attributes to the container
lv_root->set_attributes( lv_empl_att ).
* You could set attribute properties like readonly.
endif.
endif.
** check if dependent objects should be read
*    IF lv_root->check_rels_requested( ) = abap_true.
** process the directly dependent objects
*      process_children( it_requested_objects = it_request_objects
*      iv_root = lv_root ).
*    ENDIF.
*    "process foreign relations
*    process_foreign( iv_root = lv_root ).
*    "continue with the loop
lv_root = iv_root_list->get_next( ).
endwhile.
endmethod.


*************************************************************************************************

·         Create a Public Instance method SEARCH_EMPLOYEE with the following parameters



Add the following code


*************************************************************************************************

method search_employee.
data: lv_max_hits type i,
lv_string type string,
lt_search_criteria type genilt_selection_parameter_tab,
lv_last_attr_name type name_komp.
field-symbols: <search_criteria> type genilt_selection_parameter.
* NOTE:
* This is a good place to implement Authority checks!!!
*
lv_max_hits = iv_max_hits.
if lv_max_hits eq 0.
lv_max_hits = 100.
endif.
lt_search_criteria = it_search_criteria.
sort lt_search_criteria by attr_name.
loop at lt_search_criteria assigning <search_criteria>.
* NOTE: * The current implementation takes care only of CP and EQ search criteria options.
if ( <search_criteria>-option eq 'CP' or <search_criteria>-option eq 'EQ' ).
if lv_string is not initial.
if <search_criteria>-attr_name ne lv_last_attr_name.
concatenate lv_string ') AND (' into lv_string separated by space.
else.
concatenate lv_string 'OR' into lv_string separated by space.
endif.
else.
lv_string = '('.
endif.
concatenate lv_string <search_criteria>-attr_name <search_criteria>-option '''' into lv_string separated by space.
concatenate lv_string <search_criteria>-low into lv_string.
concatenate lv_string '''' into lv_string.
endif.
lv_last_attr_name = <search_criteria>-attr_name.
endloop.
refresh et_results.
if lv_string is not initial.
concatenate lv_string ')' into lv_string separated by space.
endif.
* retrieve data from the backend
call method zcl_empl_master_api=>search_employee(
exporting
iv_string   = lv_string
iv_max_hits = lv_max_hits
importing
et_results  = et_results ).
endmethod.


*************************************************************************************************

 

Our GenIL component is ready for test.

 

To test whether the Genil Object is working properly or not go to transaction GENIL_BOL_BROWSER, give component name Z_EMPL and execute. The dynamic query object ‘SearchEmployee’ will be present in Model Browser Search Objects window. Double click on it to get the search window, where you can enter search parameters and click on FIND.

Databse entries are shown in the List Browser window based on the query parameters. Double click on the individual object to see the details.

 

In my next blog I will use this GenIL component set to create a custom component with search view, result view and overview page.

19 Comments