OData and SAP Netweaver Gateway. Part IV. Association and Navigation in OData Service

Till Part III of our Tutorial series on SAP Netweaver Gateway and OData, we have designed our data models to fetch header data from EKKO and item data from EKPO independently. POHeaderSet and POItemSet do not talk to each other as of now. In real projects, we need to manipulate item data based on input from the header or other entity types and vice-versa. So there has to be a connecting link between them. In SAP Netweaver Gateway jargons, we call them Associations and we need to create Associations (and Navigation Properties) between the entity types of the data model.

Association specifies the cardinality between Entity Types. When an Association is created, a Navigation Property of the Entity Type is also generated. The Navigation tells the relationship between entities with the help of Association which it points to and the Association, in turn, tell the cardinality relationship between entities.

Let us create one Association and check how it looks in the system. Go to t-code SEGW, under Data Model, right-click on the Association folder and Create your first Association.

You need to specify the Key (Dependent Property like Foreign Key concept) between the Principal Entity and Dependent Entity.

AssociationSet is also generated, in case we want it for multiple entries (i.e tables/arrays).

Hit the Finish icon and Association, Navigation Property and Association Set are generated.

The below figure sums up the relationship between Entities, Navigation Property, Association and AssociationSet.

Do we still need to define what Navigation Properties, Association and Association Set are?

Navigation Property:
<NavigationProperty Name="HeadToItemNav"
Relationship="ZGW_PO_SRV.HeadToItemAss"
FromRole="FromRole_HeadToItemAss"
ToRole="ToRole_HeadToItemAss" />

The above code snippet and image above shows that Navigation Properties are defined for Entity Types. It points to the association type via Relationship. It also specifies the direction of flow using FromRole and ToRole. In short, Navigation Property helps to navigate between association.

Association:
- <Association Name="HeadToItemAss" sap:content-version="1">
<End Type="ZGW_PO_SRV.POHeader" Multiplicity="1" Role="FromRole_HeadToItemAss" />
<End Type="ZGW_PO_SRV.POItem" Multiplicity="*" Role="ToRole_HeadToItemAss" />
- <ReferentialConstraint>
- <Principal Role="FromRole_HeadToItemAss">
<PropertyRef Name="Ebeln" />
</Principal>
- <Dependent Role="ToRole_HeadToItemAss">
<PropertyRef Name="Ebeln" />
</Dependent>
</ReferentialConstraint>
</Association>

Similarly, the above code and the image above confirm that Association provides the cardinality (multiplicity) of the FromRole and ToRole. It, in turn, has a Referential Constraints which tell the Key field which joins/links the principal and dependent entity. FromRole and ToRole specify the Direction of flow of data. To sum up, Association is the relationship name between two entity types (one being the origin and other is destination point).

- <AssociationSet Name="HeadToItemAssSet"
Association="ZGW_PO_SRV.HeadToItemAss" sap:creatable="false"
sap:updatable="false" sap:deletable="false" sap:content-version="1">
<End EntitySet="POHeaderSet" Role="FromRole_HeadToItemAss" />
<End EntitySet="POItemSet" Role="ToRole_HeadToItemAss" />
</AssociationSet>

AssociationSet is the Association between EntitySets. This is the link between tables(arrays). As clearly visible in the above picture, Association Set points to the Association. To put it simple, AssociationSet has all the properties (cardinality, data flow direction, entity) of the associated Association.

Let us check the how the metadata of the service look after we added the above Association.

URI: /sap/opu/odata/sap/ZGW_PO_SRV/$metadata

Did you notice, the metadata has the signature of the Navigation Property of the Entity Type? Also, check the response below for the Association and AssociationSet definition.

We have been using the below URI to fetch one entry of the PO Header in our previous articles. If you try to execute the same URI again, this time, you would notice there is an additional link. This additional new link has the Query Option with the Navigation Property we created above.

URI: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500002012’)

The result of the POHeaderSet with one primary key as Query option shows a new href link. It gives the hint that we can navigate to the PO Item data by adding the Navigation Property the Query option.

If you expand one entry of the above result, you would be able to view an alternative link to get the exact one PO Item. The alternate Link to get one specific PO Item is displayed in the result of POHeaderSet query. Isn’t that useful?

URI: /sap/opu/odata/sap/ZGW_PO_SRV/POItemSet(Ebeln=’4500001729′,Ebelp=’00010′)

Que: What is the difference between the below two URIs?
URI 1: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500001729’)/HeadToItemNav
URI 2: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500001729’)?$expand=HeadToItemNav

Ans: First URI would pull the item level entries only while the second URI would pull the item level entries and also display the header level data. In short, the $expand query option is expanding the Header information with the help of the Navigation property and showing the dependent entity type.

As of now, we witnessed data flow from Header to Item. Let us introduce one more entity type which can be associated with the Item. I mean we will build a navigation link from POItem Entity to this new Entity Type. The data of this new Entity Type would be updated, deleted and created. In short this new Entity Type and Entity Set would be our Guinea Pig for our CRUD Operations in subsequent posts.

Before we create the Entity Type, let us create a simple DDIC Table ZEKKOEKPO (EKKO EKPO union) as shown below which we will use in our OData Service.

Now let us create the new Entity Type and EntitySet zekkoekpo and zekkoekpoSet respectively. Please check we have created the Entity Type zekkoekpo in lower case deliberately to show that the Entity names are case sensitive. You can check the issues which would arise due to the case of the name in subsequent posts.

By now you should know the next step. We need to implement the METHODs of the Operations we want to use for this new entity type zekkoekpo. If you still do not know how to implement and redefine the methods, then all our effort till now went in vain.

We have redefined two methods with no line of code. Let us check how our OData Service behave. For testing purpose, put external breakpoints at both the Entity Methods.

Please do not forget to re-generate your OData Project after you add/remove any Entity Type or any other component.

i. Let us call the URI which is supposed to call the GetEntitySet Method.

URI: /sap/opu/odata/sap/ZGW_PO_SRV/zekkoekpoSet

Check the GetEntitySet Method is triggered for the EntitySet Resource.

ii. Now let us call the URI which would call the GetEntity Method.

URI: /sap/opu/odata/sap/ZGW_PO_SRV/zekkoekpoSet(Ebeln=’4500003480′,Ebelp=’10’)

As expected,GetEntity Method is triggered when we pass the primary keys of the Entity.

We found, our methods get triggered even with no code in it, so now we can write our logic. Let us write simple code to extract data from EKKO and EKPO and put in our Entity Type zekkoekpo.


METHOD zekkoekposet_get_entity.
 
DATA: ls_key_tab TYPE /iwbep/s_mgw_name_value_pair,
ls_request_input_data TYPE zcl_zgw_purchase_mpc=>ts_zekkoekpo,
ls_zekkoekpo TYPE zekkoekpo,
lv_ebeln TYPE ebeln,
lv_ebelp TYPE ebelp.
* Get the key property values
READ TABLE it_key_tab WITH KEY name = 'Ebeln' INTO ls_key_tab.
IF sy-subrc = 0.
lv_ebeln = ls_key_tab-value.
ENDIF.
* Get the key property values
READ TABLE it_key_tab WITH KEY name = 'Ebelp' INTO ls_key_tab.
IF sy-subrc = 0.
lv_ebelp = ls_key_tab-value.
ENDIF.
 
IF lv_ebeln IS NOT INITIAL AND lv_ebelp IS NOT INITIAL.
SELECT SINGLE h~mandt h~ebeln i~ebelp h~bukrs h~bsart i~matnr i~werks i~meins i~menge i~loekz
FROM ( ekko AS h
INNER JOIN ekpo AS i ON h~ebeln = i~ebeln )
INTO er_entity WHERE h~ebeln = lv_ebeln
AND i~ebelp = lv_ebelp.
 
ENDIF.
 
ENDMETHOD.

Let us test this URI for the new code we implemented.

URI: /sap/opu/odata/sap/ZGW_PO_SRV/zekkoekpoSet(Ebeln=’4500003480′,Ebelp=’10’)

We are good till now. Data is fetched and displayed using our logic. Now let us create an Association between the POItem and zekkoekpo Entity Types.

Let us check the metadata again. It would show the new Navigation Property, Association and AssociationSet.
URI: /sap/opu/odata/sap/ZGW_PO_SRV/$metadata

Let us test the Navigation Property

Assume, you do not know how to frame the Query Option using the Navigation Link in the URI. Then just frame the URI for one POItemSet which you already know. Check the XML for the href. There you would have all the links to get the same value using other URI.

For this URI: /sap/opu/odata/sap/ZGW_PO_SRV/POItemSet(Ebeln=’4500003480′,Ebelp=’10’)

Check the XML for the Navigation Property.

Now let us call our URI along with the new Navigation Query Option
URI: /sap/opu/odata/sap/ZGW_PO_SRV/POItemSet(Ebeln=’4500003480′,Ebelp=’10’)/ItemToCustomNav

This is the basic about Association, Association Set and Navigation Property. Try to follow a naming convention to differentiate the Navigation and Association and Association Set. Most of us try to give the same name for Association and Navigation property. So, when we use them in URI to frame the Query Option, we are confused whether it is a Navigation Property or Association. Adding an identifier like Nav, Ass, AssSet helps to identify what you are working with.

I wanted to show some more CRUD (Create, Read, Update, Delete) Operations in this post, but I think that chapter needs more respect than just a mention. Next article would be dedicated to CRUD. We would check two-way navigation between entity types and entity sets.

We would also venture into the other Operation methods like POST, PUT, DELETE etc. As of now, we have used only GET Operation. We will populate data in our Guinea Pig Entity Type zekkoekpo and bring it to life.