This blog post will give the basic overview for beginners on the Etag topic in Odata.
E tag is used for Data Concurrency to avoid over writing of same record at the same time by different users similar to Lock objects.
Scenario for Etag
User 1 and user 2 will get the same record from backend , user 1 will update the data and save the record in database , user 2 without knowing data has been already updated to the record which he supposed to update he will update the same record and saves the data , at this time data saved by user1 will be overwritten by data of user 2 , this is not supposed to happen , this leads to data inconsistency to avoid this we will go for ETag (Entity tag) .
In etag we will have field which will uniquely identify each updating of the record whenever its updated , this field values can be generated using hash algorithm or a timestamp filed can be used to generate the etag value , which will prevent the unnecessary or concurrent updation of same record by different users at same time in this blog post we will see how can achieve this by using hash algorithm .
Created a custom table with spfli fields along with Etag Field DB table ZSPFLI_ETAG.
Custom Table ZSPFLI_ETAG with Etag
Here the field etag has the standard data type hash160 which stores the etag value .
At first There will Be no Etag values in table For newly created records.
Create a odata project and import ->DDIC Structure in form se11.
Double click on Entity type and mention etag field under Etag column as shown below.
Generate Runtime artifacts.
These Methods will be generated as shown above.
In Data provider extension add the method CALC_HASH as shown Below.
This method will have two parameters
1 .PI_DATA (impoting type ANY) for importing data from any stucture
2.PE_HASH_160(Returning type Hash160) for returning the calculated hash value for Etag.
The Function Module ‘CALCULATE_HASH_FROM_RAW’ can be used to calculate hash vaules as shown below.
After this we will redefine the method ZFLIGHTETAGSET_GET_ENTITY to get single record form db table(Zsflight_etag) and in runtime we will calculate the hash value for that record by calling CALC_HASH method and return it to ER_ENTITY.
Code In ZFLIGHTETAGSET_GET_ENTITY
method ZFLIGHTETAGSET_GET_ENTITY. data : ls_spfli type zspfli_etag , lt_spfli type table of zspfli_etag , ls_key_tab1 type /IWBEP/S_MGW_NAME_VALUE_PAIR , ls_key_tab2 type /IWBEP/S_MGW_NAME_VALUE_PAIR. read table it_key_tab into LS_KEY_TAB1 index 1. read table it_key_tab into LS_KEY_TAB2 index 2 . select single * from zspfli_etag INTO ls_spfli where CARRID = ls_key_tab1-VALUE and CONNID = ls_key_tab2-VALUE . if sy-subrc <> 0. raise EXCEPTION type /IWBEP/CX_MGW_BUSI_EXCEPTION EXPORTING textid = /IWBEP/CX_MGW_BUSI_EXCEPTION=>BUSINESS_ERROR message = 'Data of Flight schedule is not Available'. else. ls_spfli-ETAG = me->CALC_HASH( ls_spfli ). er_entity = LS_SPFLI . endif. endmethod.
Similarly we will redefine the method ZFLIGHTETAGSET_GET_ENTITYSET to get multiple record from Db table(Zsflight_etag) and in runtime we will calculate hash value for those records using CALC_HASH method and return it to ET_ENTITYSET.
Code for ZFLIGHTETAGSET_GET_ENTITYSET
method ZFLIGHTETAGSET_GET_ENTITYSET. data :lt_spfli type table of zspfli_etag , ls_spfli type zspfli_etag , TS_ZFLIGHTETAG like line of et_entityset . SELECT * from zspfli_etag into table lt_spfli . if sy-subrc = 0 and lt_spfli is not INITIAL. loop at lt_spfli into ls_spfli . ls_spfli-ETAG = me->CALC_HASH( ls_spfli ). MOVE-CORRESPONDING ls_spfli to TS_ZFLIGHTETAG. append TS_ZFLIGHTETAG to ET_ENTITYSET. clear TS_ZFLIGHTETAG. endloop . else. raise EXCEPTION type /IWBEP/CX_MGW_BUSI_EXCEPTION EXPORTING textid = /IWBEP/CX_MGW_BUSI_EXCEPTION=>BUSINESS_ERROR message = 'Data of Flight schedule is not Available'. endif. endmethod.
After Updating the Retrived Record we need to update the data to the backend db table (Zsflight_Etag) so redefine the update entity method ZFLIGHTETAGSET_UPDATE_ENTITY in this method I have written code for updating single record.
Code for ZFLIGHTETAGSET_UPDATE_ENTITY
method ZFLIGHTETAGSET_UPDATE_ENTITY. data: lv_data TYPE ZCL_ZFLIG_SHECDULE_ETA_MPC=>TS_ZFLIGHTETAG, ls_key_tab like line of it_key_tab. io_data_provider->READ_ENTRY_DATA( importing ES_DATA = lv_data ). update zspfli_etag from lv_data. if sy-subrc <> 0. raise EXCEPTION type /IWBEP/CX_MGW_BUSI_EXCEPTION EXPORTING textid = /IWBEP/CX_MGW_BUSI_EXCEPTION=>BUSINESS_ERROR message = 'Update Faild'. endif. endmethod.
After Activating all The Redefined Methods Now its item to test The ETAG functionality of the Generated service.
Our entityset Is having two key Fields . (CARRID ,CONNID).
In This case hanauser10 and hanauser12 will get the same record from the Db edit the data and they will update the data to the db .
First hanauser12 will get the data from db(Zsflight_etag)
Similarly Hanauser10 at the same time will get the data from the db(Zsflight_etag)
We can notice here that both the users hanauser12 and hanauser10 Etag value “’DECCF262A55DE81712793ACEB402F561C61D3627’” generated is same ,since both the users are in same client .
Now Hanauser12 will click on use as request button to edit the data user will change filed :Cityfrom from Chicago to Newyork.
Hanauser12 will Now add etag value in Pop Up By clicking on ADD Header Button as Shown
Fill Header Name Filed “If-Match’’.
Header Value Field W/”DECCF262A55DE81712793ACEB402F561C61D3627”’
And Upadtes The data by changing The Http PUT Method .
The data will Be Updated In backend Table with Respose 204.
Data will Be updated To the backend Table as shown below with Etag value .
Now hanauser10 will try to update the data with the same etag value W/”DECCF262A55DE81712793ACEB402F561C61D3627”’ by changing the Filed City from Nework to Denver .
And will Get the error message saying PRECONDITION FAILED with status code 412 .
This is because there is already a record in the Db(Zspflig_etag) which is updated with the same etag value that’s why system raises this error thus achiving the main purpose of Etag avoiding Data Inconsistancy.
Procedure followed by Hanauser10 to update data for same record:
If Hanauser10 wants to update the data then user has to get the New etag value by performing get operation This time user will get updted data which Hanauser12 has updated before so then Hanauser10 will update the record by New etag value .
Before user 10 updates the data to DB.
After user 10 updated the record with new etag value W/”’D30ABE6B162E68100B85545A27BC03868426EFCF’” in db.
In this scenario hanauser12 will has already updated the data once with the Etag value W/”’62D3277034FC4C90AD026137FED2B238390A45A5’” The Field: CityForm is updated to Chicago.
DB is updated As shown below.
Hanauser12 Now wants to change the Cityto Field to from SAN Francisco to Newyork so hana Hanauser12 will try to uptade with same etag value Then The system Throws error 412 since the etag value is already updated .
Hanauser12 Just wants to change the Field: Cityto value to SAN Francisco to Newyork without changing the etag value user don’t want to change the existing etag value so user will make use of
IF-None-Match content-type to achive this .
“If-None-Match” which will check the Etag present first and proceed if there is mismatch
Last updated value in db by using if none match keyword by Hanauser12 you can notice the ETAg value remain unchanged But CityTo Field value is changed to SaNFrancisco to Newyork.
Using this Etag concept we can easily identify the particular record uniquely with Etag value when the particular record is updated or changed , and avoid overwriting of data .