Create Dynamic Entity Model in SAP Gateway
Hello Everyone, this blog explains how to create Dynamic Entity type/Entity Set in SAP Gateway. We can easily create an Static entity type using Gateway service builder (SEGW). But sometimes requirements can be tricky where you need to generate Entity model at runtime. Recently, i got a requirement to develop an OData service which could not be fulfilled using static entity model.
The requirement was to create an SAPUI5 application (running on SAP OData) that will have dynamic selection screen. On execution, it should generate a dynamic report based on output fields selected by the user (relevant to the selection screen input fields). Dynamic selection screen part was easily achieved using static entity set. But the real challenge was to send multiple output records as part of odata service response since user can select any number of fields to display in the dynamic report.
The approach which i followed in developing OData service was:
- Created a static entity with properties: Field_Name, Data_Element & Table_Name. In GET_ENTITYSET method, exposed all the fields that need to be selected as part of Dynamic report.
- When an user selects output fields, application calls POST method of OData service to store relevant properties(Field_Name, Data_Element & Table_Name) in a custom table.
- Now, Create an entity with some dummy field inside it. We will change the properties of this entity at run time reading entry from the custom table. MPC_EXT class will be used here.
- Once response gets sent successfully, delete the whole custom table entries stored.
Steps:
Create a custom table (that will store user selected fields along with data element):
Insert some records for fields in the custom table:
Now, create a project ‘ZDYMANIC_ENTITY’ using t-code SEGW. Create an entity ‘TEST’ with one dummy attribute (VBELN).
Create an entityset ‘TESTSet’ for the entity. Generate runtime artifacts.
To create dynamic properties(fields) inside the entity, Redefine DEFINE method of MPC_EXT class. Create a private instance method ‘DEFINE_TEST’.
Call ‘DEFINE_TEST’ method inside DEFINE method.
DYNAMIC PROPERTIES Creation (MPC_EXT Class):
Inside the method ‘DEFINE_TEST’. Fetch the properties to be created as well as the data element (needed for binding). Loop in above properties and create properties as below:
METHOD define_test. DATA: DATA: lt_output TYPE STANDARD TABLE OF ztable_fields_op, lo_entity_type = model->create_entity_type( iv_entity_type_name = ‘TEST’ iv_def_entity_set = abap_false ). “#EC NOTEXT ********************************************************************** SELECT * FROM ztable_fields_op INTO TABLE lt_output. TRY. CALL METHOD lo_property->bind_data_element CATCH /iwbep/cx_mgw_med_exception . ********************************************************************** lo_entity_set->set_has_ftxt_search( abap_false ). ENDMETHOD. |
POPULATE Records(DPC_EXT Class):
Now, Inside DPC_EXT class, Redefine the method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_ENTITYSET to populate records in the dynamic entityset:
METHOD /iwbep/if_mgw_appl_srv_runtime~get_entityset. DATA: lt_output TYPE STANDARD TABLE OF ztable_fields_op, DATA: lt_cat TYPE TABLE OF lvc_s_fcat, FIELD-SYMBOLS : <f_fs> TYPE table. IF iv_entity_name = ‘TEST’. SELECT * FROM ztable_fields_op INTO TABLE lt_output. LOOP AT lt_output INTO ls_output. “”create a dynamic internal table ASSIGN d_ref->* TO <f_fs>. **–Fetch records dynamically ** Call methos copy_data_to_ref and export entity set data ENDIF. ENDMETHOD. |
Register the service in the gateway and test the service using Gateway client using URI /sap/opu/odata/sap/ZDYNAMIC_ENTITY_SRV/TESTSet?$format=json:
You can see status code is 200 and multiple records are coming as part of entityset in the response.
Cheers!!
I haven’t used Collections to their potential yet, but will look to check it out more closely.
Hello,
I have a question, how do you handle the cache? Because as I can know, the define method is called only when the cache is invalidated.
Regards,
Joseph
Hello Joseph,
'Define' method is used to generate metadata of the odata service. You can have a look at the code in the method (MPC class) in any Gateway project, you'll get a better understanding.
Regards,
Pranay Patel
Hi,
I understand what you did in the MPC, but what I want to say is, all the methods from MPC are executed only once when the model cache is empty/cleared. When the cache is full fill, then the define method is not executed anymore.
So if I'm rigth, you can only have a dynamic data model if you clear the cache for each call.
If it's works, i'm verry surprise and I should test it.
Regards,
Joseph
Hello,
you are absolutely right. Metadata cache will not update once it has been generated. I imagine the table to store the dynamic fields could be a customizing table. The metadata cache in gateway and backend (assuming a hub scenarioa) will not be updated if a new customizing transport has been transported to target system. In development this is not a problem because it is recommended to deactivate caching, so it will be generated again.
One way to do it however to redefine method GET_LAST_MODIFIED. However author didnt mention it and i would not recommend it.
I also disagree with the authors statement to not be able to fulfill the requirement with a static model. It is possible i have done it myself. You only need to have a static entity type which represents the "Fields". This entity set can then be filled during runtime. With deep entity you can also send those fields again back to backend and do whatever you want.
Hi Manuel,
Thanks for your inputs. To handle Metadata cache issue, we can redefine method GET_LAST_MODIFIED. I missed that point in the blog.
However, i don't agree with your statement that you can achieve it using static entity. Since you are never certain about what fields are going to be selected by the user to display in the report, how can you make an static entity with those fields. And different users can select fields of their choice in the output.
And another reason going for dynamic entity is that there can be N number of field choices (which an user can select for output), you don't want to overburden your entity with 100 fields inside it.
Regards.
Hello Pranay,
Thanks for this article. I have created a dynamic metadata on similar lines ..however, i am not able to clear the cache issue . Can you please tell about the usage of get_last_modified method in this context.
Hi Buddy,
Use the code something similar to,
DATA: lv_date TYPE timestamp.
GET TIME STAMP FIELD lv_date.
rv_last_modified = lv_date.
Regards,
Khaleel
Hi,
I've faced a similar development, and we were looking into this solution.
Cache may be one facet, but how do you handle sorting/filtering on the (dynamic) EntitySet?
Hi Frederik,
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_ENTITYSET method has all the importing paramters which you can find in normal GET method of an entityset. You can handle filter/sort in the same way as you do in normal scenario.
HI Pranay,
Very Nice article,it really makes a new learner understand how to go for a Dynamic entity set if at all required in our projects.
Thanks.
Hi Pranay,
Very nice Post, thanks for sharing.
At first glance I do not see how can I change the attributes dynamically,I mean
Let suppose that I perform a scenario to read some vbak data, just like you shown , until here it's OK, and right after I perform the same method TESTSet but I wanna to load some data from KNA1, here is the trick to me, is it possible to handle by using DEFINE method?.
How to do it ( the logic ) is clear to me but I have no parameters on DEFINE method, then my question is how to make it realy dinamically?
Regards,
If we go with above solution than data will be double means
130 Rows having 253 Columns than data rows output 32820. How you can handle the same .
Hello,
First of all thanks for this blog 🙂
I am working on a similar requirement. I used this code. For me <f_fs> table is getting populated properly with correct values for all rows and columns, but in the output all values of all columns and all rows are null. Any idea why that is?
Regards,
Naseera
Hello Naseera,
How you were able to get this project activated?
I have followed all steps but could not resolve error on the last code line.
I have replaced ER_ENTITYSET with ET_ENTITYSET as it is a get entityset method.
copy_data_to_ref( EXPORTING is_data = <f_fs>
CHANGING cr_data = et_entityset ).
Thanks,
Saurabh
Hello All,
I also faced the issue i.e. if, at all my model changes, I have to manually regenerate the OData project.
I thought of calling the DEFINE method again based on when my model changes. But, it was not at all helpful.
So, In order to resolve this. We can simply call CL_GUI_CFW => FLUSH to clear the cache.
The place where you will call this method is totally based on your requirement.
In my case, My model was changing based on the no of rows being entered in a Z table. Hence, I create an event which will trigger on saving the data. And it will refresh the cache.
And next time when you call the service with dynamic columns. It will automatically fetch the new model.
Hope it helps.
Regards,
Rajat Sharma
Hello Pranay/All,
thanks for sharing this post it was very useful.
I tried implementing dynamic entity set and its working fine, but I have 2 questions.
Thanks in advance.
Regards,
Phanindra
Hi Pranay,
Very nice Post, thanks for sharing.
Is there any way to pass the table name from URL. why because if I maintain multiple tables in custom table i will get all the table details.
My requirement is to get only table details which will pass through URL.
Thanks in advance.
Regards,
Raj
I don't understand how your Z-table should be able to distinguish users. I see no user column. And in my point of view "user" is also not enough. There should / must be some connection between the POST and the building of the model (like a request ID). Otherwise the same user can hardly use the service multiple times concurrently (e.g. in multiple tabs of a browser consuming the same service).
It contradicts also to the REST-like approach that gateway services (in my point of view) should have. Actually you have a dependency (state) between the POST and the following GET.
Can you please comment on that? In my point of view the MPC is not expecting to be used like that.
Dear Pranay Patel.
I have followed all the steps which you have showed or mentioned in above "Create Dynamic Entity Model' blogs but i can't register the service for this particular project which i have created for dynamic entity.
PFA of screenshot.