Custom entities are data definitions, which does not have a select statement on data source but we define return fields and their types. In case of custom entities their data model is invoked manually at runtime. The logic is defined in a class, we could not only retrieve data using custom entities but also do some other useful and awesome stuff with these good little tools.
For example without invoking an entire behaviour definition we need to update certain field in one of our tables which is frequently being accessed but entire data retrieval is costly due to the number of columns. In some cases we might need to trigger some specific action but we just don’t want to pass all the data from the frontend, for example we need to automate the process of completing a purchase document and all the data is readily available on our tables so fetching those data from tables and passing it again to our system would take time as well as would have an huge impact on the system. Instead we could pass the purchase order number and the rest could be handled in the class for custom entity thus minimising the backend interaction.
Yes , we have many other options for parameterised access (Data definitions with parameters) or executing a certain set of actions by invoking a data service (Data definitions with AMDP Functions) but these could not be exposed as a service or could be consumed by the frontend as a service.
Step 1: Navigate to your Project Package.
Step 2: Navigate to Core Data Services -> Data Definitions
For example without invoking an entire behaviour definition we need to update certain field in one of our tables which is frequently being accessed but entire data retrieval is costly due to the number of columns. In some cases we might need to trigger some specific action but we just don’t want to pass all the data from the frontend, for example we need to automate the process of completing a purchase document and all the data is readily available on our tables so fetching those data from tables and passing it again to our system would take time as well as would have an huge impact on the system. Instead we could pass the purchase order number and the rest could be handled in the class for custom entity thus minimising the backend interaction.
Why Custom Entities?
Yes , we have many other options for parameterised access (Data definitions with parameters) or executing a certain set of actions by invoking a data service (Data definitions with AMDP Functions) but these could not be exposed as a service or could be consumed by the frontend as a service.
Creating Custom Entities:
Step 1: Navigate to your Project Package.
Step 2: Navigate to Core Data Services -> Data Definitions
Step 3: Right click -> New Data definition
Step 4: Choose a name and description.
Step 5: Attach it to a Transport Request.
Step 6: Choose Define Custom Entity with Parameters, then choose Finish.
Step 7: It should look like this, let’s just ignore the errors for now.
Now the Data Definition part of the custom entity is done, now we have to create the class to be executed while invoking the data definition.
Step 8: Navigate to Source Code Library -> Classes
Step 9: Right click -> New ABAP Class
Step 10: Choose a name and description (Same as step 4).
Step 11: Attach it to a Transport Request (Same as step 5).
Now we have both our halves Data Definition and Class , now we have to link both .In order to this we should add a line of code at top of our Data Definition :
@ObjectModel.query.implementedBy : 'ABAP:Name of class to be invoked'
As of step 7, our Data Definition is showing errors since we didn’t assign any parameter names, return element names and their types.
In this example I am only using one parameter, as of the blog date Data Definitions only allows three parameters to be passed. In case if we want to pass more than three parameters, check the tips part at the end of this blog. I am only returning two elements in this program and literally I haven’t met any limitation for number of elements to be returned. The Custom Entities could return many number of records which is also not limited, just like an ordinary Data Definition.
Code after above changes:
@ObjectModel.query.implementedBy : 'ABAP:ZCL_CUSTOMENTITY'
define custom entity ZCustomEntity
with parameters param1 : abap.char(10)
{
key id : abap.char(10); // Returning fields are mentioned between {} just like ordinary CDS
name : abap.char(100); // Returning field set must contain a key or key combination
}
We have connected our Data Definition with our class but the class won’t work as of now, for the class to work and access the parameters passed from the definition our class must implement the standard interface IF_RAP_QUERY_PROVIDER.
Since we are implementing IF_RAP_QUERY_PROVIDER , we should try and catch two standard exceptions CX_A4C_RAP_QUERY_PROVIDER and CX_RFC_DEST_PROVIDER_ERROR.
We should also get our parameter value using io_request() and we should return our result using io_response.
Code after above changes:
class ZCL_CUSTOMENTITY definition
public
final
create public .
public section.
interfaces IF_RAP_QUERY_PROVIDER .
protected section.
private section.
endclass.
class ZCL_CUSTOMENTITY implementation.
method IF_RAP_QUERY_PROVIDER~SELECT.
data:IT_RESULT type table of ZCUSTOMENTITY. "Internal table to be returned , easier to handle return if internal table is as same type of our data definition
data: LV_PARAM type STRING."Local variable to fetch and save parameter value
try.
try.
if IO_REQUEST->IS_DATA_REQUESTED( ). "Fetching incoming data
IO_REQUEST->GET_PAGING( ).
data(LT_FILTER_COND) = IO_REQUEST->GET_PARAMETERS( ). "Setting the filter condition, fetching parameter names from data definition
LV_PARAM = value #( LT_FILTER_COND[ PARAMETER_NAME = 'param1' ]-VALUE optional ). "Fetching the parameter value
"Using the parameter we could do whatever we want , like selecting from a table , doing certain calculations etc
select * from ZEMPLOYEE where ID = LV_PARAM into IT_RESULT.
IO_RESPONSE->SET_TOTAL_NUMBER_OF_RECORDS( LINES( IT_RESULT ) ). "setting the total number of records which will be sent
IO_RESPONSE->SET_DATA( IT_RESULT ). "returning the data as internal table
endif.
catch CX_A4C_RAP_QUERY_PROVIDER into data(LX_EXC). "CX_A4C_RAP_QUERY_PROVIDER is now deprecated so use CX_RAP_QUERY_PROVIDER
endtry.
catch CX_RFC_DEST_PROVIDER_ERROR into data(LX_DEST).
endtry.
endmethod.
endclass
In order to use the custom entity we should expose the custom entity in a service binding just like our other data definitions.
After exposing and activating the custom entity data definition in service definition, it will be available in the service binding. Details about exposing, consumption and debugging will be in next blogs.
Conclusion: Custom Entities are very handy tools which helps in achieving many complex tasks easily, we could invoke the custom entity whenever we want. As I mentioned it could be used for executing a simple task like querying a table, updating a table or even triggering a complex action sequence.
Tip: In our example, we have only one parameter param1, but we need to pass four parameters. As of the blog date, we could only pass maximum of three parameters, so we could add param2, param3 to our parameter list but still we need to pass one more parameter. In order to achieve this we will concatenate our parameters separated by a flag for example ZZZ.
Ex: we need to pass four document number as a single parameter, we will be concatenating document numbers like 1001ZZZ1002ZZZ1003ZZZ1004 and will be passed to custom entity. Remember to increase the length of param1 enough to accommodate the changes.
At our class we will split the value of param1 like:
LV_PARAM1 = value #( LT_FILTER_COND[ PARAMETER_NAME = 'PARAM1' ]-VALUE optional ). “Fetching the value of parameter
split LV_PARAM1 at 'ZZZ' into table IT_PARAM1.
No comments:
Post a Comment