Hi All,
Introduction:
This blog post explains creation of simple sap gateway odata service having association and navigation between entities and also we will see how to implement it through code based approach and finally conclude with implementing of GET_EXPANDED_ENTITY and GET_EXPANDED_ENTITY_SET.
Associations Define the relationship between two or more entity Types ( For examples ,Employee Details) .Instances of associations are grouped in
Association sets.
Navigation Properties are special properties on entity Types which are bound to a specific association and can be used to refer to associations of any entity.
Finally, all instance containers (Entity sets and Association sets) are grouped in an
Entity container.
To display header details along with item details.
Procedure:
Step 1:
Go to T_code : '
SEGW'
Click on create button, the popup will open.
Click on create icon and provide the name of the project name and description and package name and click '
save'.
Step2: Create Header entity type.
For example I have created header structure.
Right click on the data model folder and import the ddic structure.
Give the entity type name and abap structure whose fields you want to import to your entity type and click on '
NEXT'.
Select the fIelds from Header table structure which you want to add to your entity type and click on '
NEXT'.
Choose the key for your structure /entity type and entity set. For examples it is
EMP_ID click on '
FINISH'.
Step 3: Create item entity type.
For example I have created item Structure.
Right click on the data model folder and import the '
DDIC STRUCTURE'.
Give the entity type name and abap structure whose fields you want to import to your entity type click on '
NEXT'.
Select the fields from structure which you want to add to your entity type, click on '
NEXT'.
Select the key for your structure /entity type and entity set . In our examples it is
EMP_ID click on '
FINISH'.
Check entity types and entity sets.
Step 4: Creating Associations and Navigation .
Expand data model and right click on associations and click on create button.
In the association you have to give
Association ,
principal type name ,
dependent entity type name and
navigation property name.
Principal entity has header entity name and
dependent entity has the item entity name.
Navigation property maps header entity to item entity (
Principal entity to dependent entity)
Provide navigation property name to access associated entity data in our odata URI (Create related navigation property checkbox will be checked by default) . After entering values to these fields click on '
NEXT'.
Select dependent property and click on '
NEXT'.
Dependent property will be the key relating two entities.
Select principle entity set and dependent entity set and click on '
FINISH'.
Finally our odata service should look like this,See navigation property is added to employee header details entity set .Also an association and association set is created .Click on generate button.
Step5: Generate objects.
Let's generate runtime artifacts ,click on generate objects button.
It will display popup click on '
CONTINUE'.
Give local package name click on '
Local Object'.
Once generation is successful, 6 classes i.e , 2 for Data provider and 2 for Model provider and 1 for Registered service and 1 for displayed.
Success message has to be displayed as shown below.
Step6:
Now open ******_DPC_EXT class and go to edit mode.
From inherited methods node
Find /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY
CREATE_DEEP_ENTITY and right click and press redefine.
It's time for some coding. Implemented CREATE_DEEP_ENTITY.
Method: /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY.
METHOD /iwbep/if_mgw_appl_srv_runtime
~create_deep_entity
.
********** Structure ************
DATA : BEGIN OF ls_order_item_data
.
INCLUDE TYPE zcl_zexpand_emp_det_02_mpc
=>ts_zemp_header_details
.
DATA : zemp_itemset
TYPE zcl_zexpand_emp_det_02_mpc
=>tt_zemp_item
,
END OF ls_order_item_data
.
********** Data Declaration ***************
DATA:
ls_headerdata
TYPE zemp_head
,
lt_headerdata
TYPE TABLE OF zemp_head
,
lt_itemdata
TYPE TABLE OF zemp_item1
,
ls_itemdata
TYPE zemp_item1
,
ls_req_itemdata
TYPE zcl_zexpand_emp_det_02_mpc
=>ts_zemp_item
,
lemp_id
TYPE zemp_id
.
********** Entity Set – HeaderSet ***********
CASE iv_entity_set_name
.
WHEN 'ZEMP_HEADER_DETAILSSet'.
io_data_provider
->read_entry_data
( IMPORTING es_data
= ls_order_item_data
).
ls_headerdata
-emp_id
= ls_order_item_data
-emp_id
.
ls_headerdata
-emp_name
= ls_order_item_data
-emp_name
.
ls_headerdata
-dept
= ls_order_item_data
-dept
.
MODIFY zemp_head
FROM ls_headerdata
.
APPEND ls_headerdata
TO lt_headerdata
.
********** Data processing logic ************
LOOP AT ls_order_item_data
-zemp_itemset
INTO ls_req_itemdata
.
MOVE-CORRESPONDING ls_req_itemdata
TO ls_itemdata
.
MODIFY zemp_item1
FROM ls_itemdata
.
APPEND ls_itemdata
TO lt_itemdata
.
ENDLOOP.
IF sy
-subrc
EQ 0.
MODIFY zemp_item1
FROM TABLE lt_itemdata
.
IF sy
-subrc
EQ 0.
********** Fill er_deep_entity ***********
copy_data_to_ref
( EXPORTING is_data
= ls_order_item_data
CHANGING cr_data
= er_deep_entity
).
ENDIF.
ENDIF.
ENDCASE.
ENDMETHOD.
Implemented GET_EXPANDED_ENTITY method.
Method: /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_EXPANDED_ENTITY.
METHOD /iwbep/if_mgw_appl_srv_runtime
~get_expanded_entity
.
********** Structure ************
DATA : BEGIN OF ls_order_item_data
.
INCLUDE TYPE zcl_zexpand_emp_det_02_mpc
=>ts_zemp_header_details
.
DATA: zemp_itemset
TYPE zcl_zexpand_emp_det_02_mpc
=>tt_zemp_item
,
END OF ls_order_item_data
.
*********** Entity Set – HeaderSet ***********
CASE iv_entity_set_name
.
WHEN 'ZEMP_HEADER_DETAILSSet'.
DATA(ls_key_tab
) = it_key_tab[ name
= 'EmpId' ]
.
IF sy
-subrc
= 0.
DATA(lemp_id
) = ls_key_tab
-value.
ENDIF.
SELECT SINGLE *
FROM zemp_head
INTO @DATA(ls_headerdata
) WHERE emp_id
= @lemp_id
.
SELECT *
FROM zemp_item1
INTO TABLE @DATA(lt_itemdata
) WHERE emp_id
= @lemp_id
.
MOVE-CORRESPONDING ls_headerdata
TO ls_order_item_data
.
ls_order_item_data
-emp_id
= '1000'.
************ fill er_entity **********
MOVE-CORRESPONDING lt_itemdata
TO ls_order_item_data
-zemp_itemset
.
ls_order_item_data
-zemp_itemset[
1 ]
-age
= '22'.
copy_data_to_ref
( EXPORTING is_data
= ls_order_item_data
CHANGING cr_data
= er_entity
).
ENDCASE.
ENDMETHOD.
Implemented GET_EXPANDED_ENTITYSET method.
Method: /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_EXPANDED_ENTITYSET.
METHOD /iwbep/if_mgw_appl_srv_runtime
~get_expanded_entityset
.
*********** Structure ************
DATA : BEGIN OF ls_order_item_data
.
INCLUDE TYPE zcl_zexpand_emp_det_02_mpc
=>ts_zemp_header_details
.
DATA: zemp_itemset
TYPE zcl_zexpand_emp_det_02_mpc
=>tt_zemp_item
,
END OF ls_order_item_data
.
DATA: lt_order_item_data
LIKE TABLE OF ls_order_item_data
.
*********** Entity Set – HeaderSet ***********
CASE iv_entity_set_name
.
WHEN 'ZEMP_HEADER_DETAILSSet'.
SELECT *
FROM zemp_head
INTO TABLE @DATA(lt_header
).
SELECT *
FROM zemp_item1
INTO TABLE @DATA(lt_item
).
IF sy
-subrc
EQ 0.
************* Data processing logic *********
LOOP AT lt_header
INTO DATA(ls_header
).
MOVE-CORRESPONDING ls_header
TO ls_order_item_data
.
LOOP AT lt_item
INTO DATA(ls_item
) WHERE emp_id
= ls_header
-emp_id
.
MOVE-CORRESPONDING ls_item
TO ls_order_item_data
.
APPEND ls_item
TO ls_order_item_data
-zemp_itemset
.
CLEAR ls_item
.
ENDLOOP.
APPEND ls_order_item_data
TO lt_order_item_data
.
CLEAR ls_order_item_data
.
ENDLOOP.
ENDIF.
DATA(lv_techname
) = 'EMPITEMSET'.
APPEND lv_techname
TO et_expanded_tech_clauses
.
************** Fill er_entityset ************
copy_data_to_ref
( EXPORTING is_data
= lt_order_item_data
CHANGING cr_data
= er_entityset
).
ENDCASE.
ENDMETHOD.
Step7:
Let's register service maintenance ,click on register service button
.
Click on
' Maintain Services'.
Click on '
Gateway Client '.
Metadata:
We have created the service and activated it. Now we can test using Gateway client (/IWFND/GW_CLIENT).
URI:' /sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/$metadata ' And execute.
OUTPUT :
Now we can test in gateway client (/
IWFND/GW_CLIENT).Our service URL look like.
If you have observed the URL parameter $EXPAND ,you must have noticed that the path passed explains the hierarchy form HEADER to ITEM with $EXPAND = ZEMP_HEADER_DETAILSSet TO ZEMP_ITEM SET.
This $EXPAND expression tells the framework to map multi level associated entity sets to the output result from the GET_EXPANDED_ENTITYSET method of the DPC.
In turn, the framework maps corresponding fields in the output result with the name same as the Navigation property of the entity sets.
URI: /sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet?$expand=ZEMP_ITEMSet&$format=json.
URI: /sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet?$expand=ZEMP_ITEMSet&$format=json.
{
"d" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1000')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1000')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_HEADER_DETAILS"
},
"EmpId" :
"1000",
"EmpName" :
"Naveen",
"Dept" :
"SAP",
"ZEMP_ITEMSet" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1000')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1000')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_ITEM"
},
"EmpId" :
"1000",
"Age" :
"00025",
"City" :
"HYD"
}
]
}
},
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1001')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1001')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_HEADER_DETAILS"
},
"EmpId" :
"1001",
"EmpName" :
"Ram",
"Dept" :
"SAP",
"ZEMP_ITEMSet" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1001')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1001')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_ITEM"
},
"EmpId" :
"1001",
"Age" :
"00029",
"City" :
"HYD"
}
]
}
},
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1002')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1002')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_HEADER_DETAILS"
},
"EmpId" :
"1002",
"EmpName" :
"Sarath",
"Dept" :
"SAP",
"ZEMP_ITEMSet" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1002')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1002')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_ITEM"
},
"EmpId" :
"1002",
"Age" :
"00035",
"City" :
"HYD"
}
]
}
},
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1003')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1003')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_HEADER_DETAILS"
},
"EmpId" :
"1003",
"EmpName" :
"Ashok",
"Dept" :
"SAP",
"ZEMP_ITEMSet" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1003')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1003')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_ITEM"
},
"EmpId" :
"1003",
"Age" :
"00031",
"City" :
"HYD"
}
]
}
},
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1004')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1004')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_HEADER_DETAILS"
},
"EmpId" :
"1004",
"EmpName" :
"Naresh",
"Dept" :
"ABAP",
"ZEMP_ITEMSet" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1004')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1004')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_ITEM"
},
"EmpId" :
"1004",
"Age" :
"00039",
"City" :
"HYD"
}
]
}
},
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1005')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_HEADER_DETAILSSet('1005')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_HEADER_DETAILS"
},
"EmpId" :
"1005",
"EmpName" :
"Krishna",
"Dept" :
"ABAP",
"ZEMP_ITEMSet" : {
"results" : [
{
"__metadata" : {
"id" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1005')",
"uri" :
"http://BISERVER:8009/sap/opu/odata/sap/ZEXPAND_EMP_DETAILS_SRV_02/ZEMP_ITEMSet('1005')",
"type" :
"ZEXPAND_EMP_DETAILS_SRV_02.ZEMP_ITEM"
},
"EmpId" :
"1005",
"Age" :
"00038",
"City" :
"HYD"
}
]
}
}
]
}
Conclusion:
Important points to be considered while coding for association/navigation and data provider$expand,
Use of navigation path and navigation key, entities can be directly accessed or Via navigation property . code for both scenario using navigation path and navigation keys.
Whether framework expand or data provider expand provides better result will depends on your scenario .
I hope you enjoyed reading this blog and now will be able to play with association/navigation and $expand.
Please feel free if you have any different thoughts to improve any section of this blog post.
Thanks.
Appreciate your suggestion and comments.