SAP ABAP Development, SAP Fiori, SAP Fiori tools

Fiori Elements: Perform Crud operation by using OData annotation Code-Based

In this blog you will understand how to create OData annotations in SEGW with example and consume the service in visual studio and display the output in Fiori launchpad also will perform the crud operation.

Here, we had a requirement to perform the crud operation in Fiori Application by using OData code-based annotations, usually we are performing the crud operation using CDs annotation by defining the Business Object in CDs view similarly we can write the annotation in OData project as well. First time it feels like Complex but once you start with that you will be okay with that

However, we are Defining the OData annotation to Service, we supposed to write code in MPC_EXT class inside Define Method (redefine the Method)

Let’s begin with OData Service creation

Database table

@EndUserText.label : 'Employee Master data'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zpremployee {
  key client : mandt not null;
  key eid    : sysuuid_x16 not null;
  fname      : abap.char(50);
  lname      : abap.char(50);
  gender     : abap.char(20);
  dept       : abap.char(50);
  status     : abap.char(1);
  doj        : abap.dats;
  dob        : abap.dats;
  age        : abap.char(3);
  salary     : abap.int8;
  currency   : abap.cuky;
  ratings    : abap.dec(10,2);

}

Create OData Project In a Gateway Service Builder transaction and define your entity.

Once you defined the entity types make sure that artifacts must be generated.

However, your entities methods are getting generated based on your entities inside DPC_EXT Class so just provide the implementation(redefine) for those to perform the Crud operation.

Follow the below code to implement the entities for respective operation.

Get_EntitySet( for retrieve all the records from the database):

Get_Entity (for retrieve the single records from database) :

method zpremployeeset_get_entity.  
* To fetch Single record based on the key in the URI

    assign it_key_tab[ name = 'Eid' ] to field-symbol(<lfs>).
    if  <lfs> is assigned.
      select SINGLE * from zpremployee into  er_entity where eid = <lfs>-value.
    endif.
  endmethod.

Create_Entity (for creating new record) :

method zpremployeeset_create_entity.
    data : ls_employee TYPE ZCL_ZPR_EMPLOYEE_SRC_MPC=>TS_ZPREMPLOYEE.
    io_data_provider->read_entry_data(
      importing
        es_data = ls_employee
    ).

    IF ls_employee is NOT INITIAL.
     ls_employee-eid = new cl_system_uuid( )->if_system_uuid~create_uuid_x16( ).
      IF ls_employee-eid is NOT INITIAL.
       INSERT zpremployee from ls_employee.
      ENDIF.
    ENDIF.
endmethod.

Update_Entity (For update particular record):

method zpremployeeset_update_entity.
data : ls_employee type zcl_zpr_employee_src_mpc=>ts_zpremployee.
io_data_provider->read_entry_data(
importing
es_data = ls_employee
).

if ls_employee is not initial.
  if ls_employee-eid is not initial.
    update zpremployee from ls_employee .
  endif.
endif.

endmethod.

Delete_Entity ( for delete the record)

method zpremployeeset_delete_entity.
    data : ls_employee type zcl_zpr_employee_src_mpc=>ts_zpremployee.
    break-point.
    assign it_key_tab[ name = 'Eid' ] to field-symbol(<lfs>).
    if <lfs> is assigned.
      ls_employee-eid = <lfs>-value.
      if ls_employee is not initial.
        delete zpremployee from ls_employee.
      endif.
    endif
endmethod.

Once you done with your implementation just maintain and activate your service in Gateway Builder.

Click on Register Button it will open new session there provide your package and click on Continue to activate the service.

Once your service Registered successfully select your service and click on SAP Gateway Client.

In Gateway client select the URI Option $metadata and select the HTTP Method GET and click on execute.

Once you got the response with status code 200 validate the properties that you defined in the entity type, if you are getting all the properties in response tab then you can conclude service will behave as expected.

If you want to test your service you can perform the operation here once before proceeding further.

Here will see how to create Fiori app by using visual studio code.

Before start with the process, you make sure to have the extension packages in VS code then only we are able to create the Fiori app.

Open VS Code Goto view in the menu and click on command palatte(ctrl+shift+P), after search

Fiori : Open Application Generator; it will open template Wizard

Select one template based on your requirement.

Then Connect your backend system

If you are not registered you have to register your backend system else you can go with OData service directly.

After provide your OData service name and click on next button.

Once done select your main entity in the entity selection step then click on next.

After provide project name and project title then click on finish.

Once Done it will install some required dependencies to the Fiori Application

After that preview your application.

It will open your application in the browser as below.

To enable the default search option by default in fiori application you must have to check the searchble check in your entity set definition.

Then generate your project once done with that, open your browser and refresh your application then you are able search option as show in below image.

Here we are performing the crud operation on one entity, however I will enable the create,delete,update options.

Make sure your project needs to generate artifacts when you made any changes in your definitions.

If you want display the default HeaderInfo inside app you just write the annotation inside define method of MPC_EXT Class

Here, I have taken vocabulary reference to display the default columns.

Just redefine Define Method and add the below code.

method define.
    super->define( ). 

    data: lo_ann_target  type ref to /iwbep/if_mgw_vocan_ann_target,   " Vocabulary Annotation Target
          lo_collection  type ref to /iwbep/if_mgw_vocan_collection,  " Vocabulary Annotation Collection
          lo_record      type ref to /iwbep/if_mgw_vocan_record.       " Vocabulary Annotation Record

    me->vocab_anno_model->create_vocabulary_reference( iv_vocab_id      = '/IWBEP/VOC_UI'
                                                       iv_vocab_version = '1')->create_include( iv_namespace = 'com.sap.vocabularies.UI.v1'
                                                                                                iv_alias     = 'UI' ).

    lo_ann_target = me->vocab_anno_model->create_annotations_target( iv_target  = 'zpremployee' ).                " Target: The Element a Vocabulary Annotation points to
    lo_ann_target->set_namespace_qualifier( 'ZPR_EMPLOYEE_SRC_SRV' ).

    lo_record = lo_ann_target->create_annotation( iv_term = 'UI.HeaderInfo' )->create_record( ).                  "UI.HeaderInfo Annotatoin

    lo_record->create_property('TypeName')->create_simple_value( )->set_string( iv_value = 'Employee Details'  ).
    lo_record->create_property('TypeNamePlural')->create_simple_value( )->set_string( iv_value = 'Employees'  ).
endmethod.

You can see the Header info once you refresh your application.

If you want display the default columns when application is launched just add the UI.LineItems reference in your code, then bind respected properties based on your requirement.

lo_collection = lo_ann_target->create_annotation( iv_term = 'UI.LineItem' )->create_collection( ).  "UI.Lineitem Annotation

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'First Name' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Fname' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Last Name' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Lname' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Department' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Dept' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Date-of-join' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Doj' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Salary' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Salary' ).

based on property binding using collection will be displayed in fiori app, if you want see the data click-on Go Button.

If you try to open object page you will be getting empty page to avoid that create some UI,Identification annotation.

Just refer the below code to display the properties in object page.

lo_collection = lo_ann_target->create_annotation( iv_term = 'UI.Facets' )->create_collection( ).          "Header Facets

    lo_record = lo_collection->create_record( iv_record_type = 'UI.ReferenceFacet' ).
    lo_record->create_property( 'ID' )->create_simple_value( )->set_string( 'GeneralInformation' ).
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( 'General Information' ).
    lo_record->create_property( 'Target')->create_simple_value( )->set_annotation_path( '@UI.Identification' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.ReferenceFacet' ).
    lo_record->create_property( 'ID' )->create_simple_value( )->set_string( 'JOBID' ).
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( 'Job Description' ).
    lo_record->create_property( 'Target')->create_simple_value( )->set_annotation_path( '@UI.Identification' ).

This reference will help to display tab name in object page called as facet tabs.

Display the fields under the facet with help of UI.facet annotation also you need to make use of the UI.identification annotation to display the required fields data in object page.

lo_collection = lo_ann_target->create_annotation( iv_term = 'UI.Identification' )->create_collection( ). "UI.Identification Annotatoin

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'First Name' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Fname' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Last Name' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Lname' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Gender' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Gender' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Date-of-birth' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Dob' ).
*
    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Age' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Age' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Department' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Dept' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Date-of-join' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Doj' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Joining Status' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Status' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Salary' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Salary' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Currency' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Currency' ).

    lo_record = lo_collection->create_record( iv_record_type = 'UI.DataField').
    lo_record->create_property( 'Label' )->create_simple_value( )->set_string( iv_value = 'Ratings' ).
    lo_record->create_property( 'Value' )->create_simple_value( )->set_path( iv_value = 'Ratings' ).

When you check the creatable check box in entity definition in data model it will shows mandatory behavior for properties in Fiori app as shown below.

All the fields are displayed as mandatory when your try to create a record or update the record.

If you want to make optional then you must have to make use Nullable check box.

Now all the fields are behaving as an optional one by concluding this is what we can observe the difference by property level.

If you made any properties as filter by checking the filterable check box, you can see those properties in adopt filter option, that property is able to become a filter for the report but not by default.

Fields will become a basic filter in Fiori app.

You can perform the crud operation now it will be going to maintain the data inside database via service

Create Operation :

Enter the data that you want insert into data base and click on Create Button.

if entered data is in consistant then i well going to create the records and shows the message as below.

You can see the new employee name ‘Jack Routen’ has joined to analyst department.

Put Operation

Once you made the changes on particular record then click on save button.

if you made any changes to existing record the i will shows the message as below.

Delete Operation

Select the record that you want to delete and click on delete button.

click on delete button again.

if it deleted successfully, you will see the message as shown below.