Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
12,687

I got a requirement to build OData service to fetch the data from DFKKKO and DFKKOP tables using OData V4. Using SEGW we can build OData V2 and finish it within the given time. After spending some time, I came to know that we should not use SEGW to create an OData V4. It is not recommended by SAP as of now. We have to use Code Based Implementation approach to create an OData V4 service. Thanks to Andre Fischer for writing 3 blogs on OData V4 Code Based Implementation. I’m writing this blog to help the beginners to easily understand OData V4 Code Based Implementation.


Here are steps to create an OData V4 service using Code Based Implementation.

1. Create 2 CDS views one for header and other one for items.

1.1 ZFICA_DFKKKO_V – Header CDS View
@AbapCatalog.sqlViewName: 'ZFICA_DFKKKO_V'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Header Data in Open Item Accounting Document'
define view ZFICA_DFKKKO as select from dfkkko
association [1..*] to ZFICA_DFKKOP as _Item on _Item.opbel = $projection.opbel
{
key opbel,
fikey,
applk,
blart,
herkf,
ernam,
cpudt,
cputm,
/* Associations */
_Item
}

1.2 ZFICA_DFKKOP_V – Items CDS View.
@AbapCatalog.sqlViewName: 'ZFICA_DFKKOP_V'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Items in contract account document'
define view ZFICA_DFKKOP as select from dfkkop
key opbel,
key opupw,
key opupk,
key opupz,
bukrs,
gsber,
bupla,
segment
}

2. Create an Interface using the CDS views.
interface ZIF_DFKKOP_ODATA_V4_TYPES
public .
types:
begin of gty_cds_views,
accItem type ZFICA_DFKKOP,
accHeader type ZFICA_DFKKKO,
end of gty_cds_views.

types: begin of gty_s_ko_kop .
include type gty_cds_views-accheader.
types:
_item type standard table of gty_cds_views-accitem with default key,
end of GTY_S_KO_KOP .

types:
begin of gt_key_range,
opbel type range of gty_cds_views-accheader-opbel,
opupw type range of gty_cds_views-accitem-opupw,
end of gt_key_range.

constants:

begin of gcs_cds_view_names,
accItem type /iwbep/if_v4_med_element=>ty_e_med_internal_name value 'ZFICA_DFKKOP',
accHeader type /iwbep/if_v4_med_element=>ty_e_med_internal_name value 'ZFICA_DFKKKO',
end of gcs_cds_view_names,

begin of gcs_entity_type_names,
begin of internal,
accItem type /iwbep/if_v4_med_element=>ty_e_med_internal_name value 'ZFICA_DFKKOP',
accHeader type /iwbep/if_v4_med_element=>ty_e_med_internal_name value 'ZFICA_DFKKKO',
end of internal,
begin of edm,
accItem type /iwbep/if_v4_med_element=>ty_e_med_edm_name value 'AccItemType',
accHeader type /iwbep/if_v4_med_element=>ty_e_med_edm_name value 'AccHeaderType',
end of edm,
end of gcs_entity_type_names,

begin of gcs_entity_set_names,
begin of internal,
accItem type /iwbep/if_v4_med_element=>ty_e_med_internal_name value 'ZFICA_DFKKOP',
accHeader type /iwbep/if_v4_med_element=>ty_e_med_internal_name value 'ZFICA_DFKKKO',
end of internal,
begin of edm,
accItem type /iwbep/if_v4_med_element=>ty_e_med_edm_name value 'AccItem',
accHeader type /iwbep/if_v4_med_element=>ty_e_med_edm_name value 'AccHeader',
end of edm,
end of gcs_entity_set_names ,

begin of gcs_nav_prop_names,
begin of internal,
accheader_to_items type /iwbep/if_v4_med_element=>ty_e_med_internal_name value '_ITEM',
end of internal,
begin of edm,
accheader_to_items type /iwbep/if_v4_med_element=>ty_e_med_edm_name value '_Item',
end of edm,
end of gcs_nav_prop_names.

endinterface.

3. Create a Model Provider class.
CLASS zcl_dfkkkop_odata_v4_model DEFINITION
PUBLIC
inheriting from /iwbep/cl_v4_abs_model_prov
FINAL
CREATE PUBLIC .

PUBLIC SECTION.
interfaces zif_DFKKOP_odata_v4_types.
methods /iwbep/if_v4_mp_basic~define redefinition.

PROTECTED SECTION.
PRIVATE SECTION.

aliases gty_cds_views
for zif_DFKKOP_odata_v4_types~gty_cds_views.
aliases gcs_entity_set_names
for zif_DFKKOP_odata_v4_types~gcs_entity_set_names .
aliases gcs_entity_type_names
for zif_DFKKOP_odata_v4_types~gcs_entity_type_names .
aliases gcs_nav_prop_names
for zif_DFKKOP_odata_v4_types~gcs_nav_prop_names.

methods define_accHeader
importing
io_model type ref to /iwbep/if_v4_med_model
raising
/iwbep/cx_gateway .

methods define_accItem
importing
io_model type ref to /iwbep/if_v4_med_model
raising
/iwbep/cx_gateway .

ENDCLASS.



CLASS zcl_dfkkkop_odata_v4_model IMPLEMENTATION.

method /iwbep/if_v4_mp_basic~define.
define_accHeader( io_model ).
define_accItem( io_model ).
endmethod.

method define_accHeader.
data: lt_primitive_properties type /iwbep/if_v4_med_element=>ty_t_med_prim_property,
lo_entity_set type ref to /iwbep/if_v4_med_entity_set,
lo_nav_prop type ref to /iwbep/if_v4_med_nav_prop,
lo_entity_type type ref to /iwbep/if_v4_med_entity_type,
lv_referenced_cds_view type gty_cds_views-accheader . " As internal ABAP name we use the name of the CDS view

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Create entity type
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_type = io_model->create_entity_type_by_struct(
exporting
iv_entity_type_name = gcs_entity_type_names-internal-accheader
is_structure = lv_referenced_cds_view
iv_add_conv_to_prim_props = abap_true
iv_add_f4_help_to_prim_props = abap_true
iv_gen_prim_props = abap_true ).

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set external EDM name for entity type
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_type->set_edm_name( gcs_entity_type_names-edm-accheader ).

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Rename external EDM names of properties so that CamelCase notation is used
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_type->get_primitive_properties( importing et_property = lt_primitive_properties ).

loop at lt_primitive_properties into data(lo_primitive_property).
lo_primitive_property->set_edm_name( to_mixed( val = lo_primitive_property->get_internal_name( ) ) ).
endloop.

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set key field(s)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_primitive_property = lo_entity_type->get_primitive_property( 'OPBEL' ).
lo_primitive_property->set_is_key( ).


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Create navigation property
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_nav_prop = lo_entity_type->create_navigation_property( gcs_nav_prop_names-internal-accheader_to_items ).
lo_nav_prop->set_edm_name( gcs_nav_prop_names-edm-accheader_to_items ).

lo_nav_prop->set_target_entity_type_name( gcs_entity_type_names-internal-accitem ).
lo_nav_prop->set_target_multiplicity( /iwbep/if_v4_med_element=>gcs_med_nav_multiplicity-to_many_optional ).
lo_nav_prop->set_on_delete_action( /iwbep/if_v4_med_element=>gcs_med_on_delete_action-none ).

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Create entity set
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_set = lo_entity_type->create_entity_set( gcs_entity_set_names-internal-accheader ).
lo_entity_set->set_edm_name( gcs_entity_set_names-edm-accheader ).

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Add the binding of the navigation path
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_set->add_navigation_prop_binding( iv_navigation_property_path = conv #( gcs_nav_prop_names-internal-accheader_to_items )
iv_target_entity_set = gcs_entity_set_names-internal-accitem ).

endmethod.

method define_accItem.
data: lo_entity_type type ref to /iwbep/if_v4_med_entity_type,
lo_entity_set type ref to /iwbep/if_v4_med_entity_set,
lt_primitive_properties type /iwbep/if_v4_med_element=>ty_t_med_prim_property,
lv_referenced_cds_view type gty_cds_views-accitem . " As internal ABAP name we use the name of the CDS view


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Create entity type
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_type = io_model->create_entity_type_by_struct(
exporting
iv_entity_type_name = gcs_entity_type_names-internal-accitem
is_structure = lv_referenced_cds_view
iv_add_conv_to_prim_props = abap_true
iv_add_f4_help_to_prim_props = abap_true
iv_gen_prim_props = abap_true ).

lo_entity_type->set_edm_name( gcs_entity_type_names-edm-accitem ).

lo_entity_type->get_primitive_properties( importing et_property = lt_primitive_properties ).

loop at lt_primitive_properties into data(lo_primitive_property).
lo_primitive_property->set_edm_name( to_mixed( val = lo_primitive_property->get_internal_name( ) ) ).
endloop.

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set key field(s)
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_primitive_property = lo_entity_type->get_primitive_property( 'OPBEL' ).
lo_primitive_property->set_is_key( ).

lo_primitive_property = lo_entity_type->get_primitive_property( 'OPUPW' ).
lo_primitive_property->set_is_key( ).


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Create entity set
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
lo_entity_set = lo_entity_type->create_entity_set( gcs_entity_set_names-internal-accitem ).
lo_entity_set->set_edm_name( gcs_entity_set_names-edm-accitem ).

endmethod.
ENDCLASS.

4. Create a Data Provider Class.
CLASS zcl_dfkkkop_odata_v4_data DEFINITION
PUBLIC
inheriting from /iwbep/cl_v4_abs_data_provider
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

interfaces zif_dfkkop_odata_v4_types.

methods /iwbep/if_v4_dp_basic~read_entity redefinition .
methods /iwbep/if_v4_dp_basic~read_entity_list redefinition.
methods /iwbep/if_v4_dp_basic~read_ref_target_key_data_list redefinition .

PROTECTED SECTION.
PRIVATE SECTION.

aliases gcs_entity_set_names
for zif_dfkkop_odata_v4_types~gcs_entity_set_names .
aliases gcs_entity_type_names
for zif_dfkkop_odata_v4_types~gcs_entity_type_names .
aliases gty_cds_views
for zif_dfkkop_odata_v4_types~gty_cds_views.
aliases gcs_nav_prop_names
for zif_dfkkop_odata_v4_types~gcs_nav_prop_names.

methods read_list_accheader
importing
io_request type ref to /iwbep/if_v4_requ_basic_list
io_response type ref to /iwbep/if_v4_resp_basic_list
iv_orderby_string type string
iv_where_clause type string
iv_select_string type string
iv_skip type i
iv_top type i
is_done_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_process_list
raising
/iwbep/cx_gateway.


methods read_entity_accheader
importing
io_request type ref to /iwbep/if_v4_requ_basic_read
io_response type ref to /iwbep/if_v4_resp_basic_read
raising
/iwbep/cx_gateway.

methods read_ref_key_list_accheader
importing
io_request type ref to /iwbep/if_v4_requ_basic_ref_l
io_response type ref to /iwbep/if_v4_resp_basic_ref_l
raising
/iwbep/cx_gateway.

methods read_list_accitem
importing
io_request type ref to /iwbep/if_v4_requ_basic_list
io_response type ref to /iwbep/if_v4_resp_basic_list
iv_orderby_string type string
iv_where_clause type string
iv_select_string type string
iv_skip type i
iv_top type i
is_done_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_process_list
raising
/iwbep/cx_gateway.

methods read_entity_accitem
importing
io_request type ref to /iwbep/if_v4_requ_basic_read
io_response type ref to /iwbep/if_v4_resp_basic_read
raising
/iwbep/cx_gateway.




ENDCLASS.



CLASS zcl_dfkkkop_odata_v4_data IMPLEMENTATION.



method /iwbep/if_v4_dp_basic~read_entity.

data: lv_entityset_name type /iwbep/if_v4_med_element=>ty_e_med_internal_name.


io_request->get_entity_set( importing ev_entity_set_name = lv_entityset_name ).

case lv_entityset_name.

when gcs_entity_set_names-internal-accheader.
read_entity_accheader(
exporting
io_request = io_request
io_response = io_response ).

when gcs_entity_set_names-internal-accitem.
read_entity_accitem(
exporting
io_request = io_request
io_response = io_response ).

when others.
super->/iwbep/if_v4_dp_basic~read_entity(
exporting
io_request = io_request
io_response = io_response ).

endcase.

endmethod.

method /iwbep/if_v4_dp_basic~read_entity_list.

data lv_entityset_name type /iwbep/if_v4_med_element=>ty_e_med_internal_name.

data: ls_todo_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_list,
ls_done_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_process_list,
lv_where_clause type string,
lv_select_string type string,
lv_orderby_string type string,
lt_selected_property type /iwbep/if_v4_runtime_types=>ty_t_property_path,
lv_skip type i value 0,
lv_top type i value 0,
lt_orderby_property type abap_sortorder_tab.


io_request->get_todos( importing es_todo_list = ls_todo_list ).

if ls_todo_list-process-orderby = abap_true.
ls_done_list-orderby = abap_true.

io_request->get_orderby( importing et_orderby_property = lt_orderby_property ).
clear lv_orderby_string.
loop at lt_orderby_property into data(ls_orderby_property).
if ls_orderby_property-descending = abap_true.
concatenate lv_orderby_string ls_orderby_property-name 'DESCENDING' into lv_orderby_string separated by space.
else.
concatenate lv_orderby_string ls_orderby_property-name 'ASCENDING' into lv_orderby_string separated by space.
endif.
endloop.

else.
" lv_orderby_string must not be empty.
lv_orderby_string = 'PRIMARY KEY'.
endif.


" $skip / $top handling
if ls_todo_list-process-skip = abap_true.
ls_done_list-skip = abap_true.
io_request->get_skip( importing ev_skip = lv_skip ).
endif.
if ls_todo_list-process-top = abap_true.
ls_done_list-top = abap_true.
io_request->get_top( importing ev_top = lv_top ).
endif.


" $select handling
if ls_todo_list-process-select = abap_true.
ls_done_list-select = abap_true.
io_request->get_selected_properties( importing et_selected_property = lt_selected_property ).
concatenate lines of lt_selected_property into lv_select_string separated by ','.
else.
"check coding. If no columns are specified via $select retrieve all columns from the model instead?
lv_select_string = '*'.
"or better to throw an exception instead?
endif.


" specific sales orders based on $filter?
if ls_todo_list-process-filter = abap_true.
ls_done_list-filter = abap_true.
io_request->get_filter_osql_where_clause( importing ev_osql_where_clause = lv_where_clause ).
endif.

io_request->get_entity_set( importing ev_entity_set_name = lv_entityset_name ).

case lv_entityset_name.

when gcs_entity_set_names-internal-accheader.

read_list_accheader(
exporting
io_request = io_request
io_response = io_response
iv_orderby_string = lv_orderby_string
iv_select_string = lv_select_string
iv_where_clause = lv_where_clause
iv_skip = lv_skip
iv_top = lv_top
is_done_list = ls_done_list ).

when gcs_entity_set_names-internal-accitem.

read_list_accitem(
exporting
io_request = io_request
io_response = io_response
iv_orderby_string = lv_orderby_string
iv_select_string = lv_select_string
iv_where_clause = lv_where_clause
iv_skip = lv_skip
iv_top = lv_top
is_done_list = ls_done_list ).

when others.

super->/iwbep/if_v4_dp_basic~read_entity_list( io_request = io_request
io_response = io_response ).
endcase.


endmethod.

method /iwbep/if_v4_dp_basic~read_ref_target_key_data_list.

data: lv_source_entity_name type /iwbep/if_v4_med_element=>ty_e_med_internal_name.


io_request->get_source_entity_type( importing ev_source_entity_type_name = lv_source_entity_name ).

case lv_source_entity_name.

when gcs_entity_type_names-internal-accheader.
read_ref_key_list_accheader(
exporting
io_request = io_request
io_response = io_response ).

when others.
super->/iwbep/if_v4_dp_basic~read_ref_target_key_data_list(
exporting
io_request = io_request
io_response = io_response ).

endcase.

endmethod.

method read_entity_accheader.

"entity type specific data types
data: ls_accheader type gty_cds_views-accheader,
ls_key_accheader type gty_cds_views-accheader,
lv_accheader_key_edm type string,
lv_helper_int type i.
"generic data types
data: ls_todo_list type /iwbep/if_v4_requ_basic_read=>ty_s_todo_list,
ls_done_list type /iwbep/if_v4_requ_basic_read=>ty_s_todo_process_list.

io_request->get_todos( importing es_todo_list = ls_todo_list ).

" read the key data
io_request->get_key_data( importing es_key_data = ls_key_accheader ).
ls_done_list-key_data = abap_true.

select single * from zFICA_DFKKKO
into corresponding fields of @ls_accheader
where opbel = @ls_key_accheader-opbel.

if ls_accheader is not initial.
io_response->set_busi_data( is_busi_data = ls_accheader ).
else.
"Move data first to an integer to remove leading zeros from the response
lv_accheader_key_edm = lv_helper_int = ls_key_accheader-opbel.

endif.

" Report list of request options handled by application
io_response->set_is_done( ls_done_list ).
endmethod.

method read_entity_accitem.
"entity type specific data types
data: ls_accitem type gty_cds_views-accitem,
ls_key_accitem type gty_cds_views-accitem,
lv_key_edm_accitem type string,
lv_helper_int type i.
"generic data types
data: ls_todo_list type /iwbep/if_v4_requ_basic_read=>ty_s_todo_list,
ls_done_list type /iwbep/if_v4_requ_basic_read=>ty_s_todo_process_list.

io_request->get_todos( importing es_todo_list = ls_todo_list ).

" read the key data
io_request->get_key_data( importing es_key_data = ls_key_accitem ).
ls_done_list-key_data = abap_true.

select single * from ZFICA_DFKKOP
into corresponding fields of @ls_accitem
where opbel = @ls_key_accitem-opbel
and OPUPW = @ls_key_accitem-OPUPW.

if ls_accitem is not initial.
io_response->set_busi_data( is_busi_data = ls_accitem ).
else.
"Move data first to an integer to remove leading zeros from the response
lv_key_edm_accitem = lv_helper_int = ls_key_accitem-opbel.
lv_key_edm_accitem = lv_key_edm_accitem && ','.
lv_helper_int = ls_key_accitem-opbel.
lv_key_edm_accitem = lv_key_edm_accitem && lv_helper_int.

endif.

" Report list of request options handled by application
io_response->set_is_done( ls_done_list ).
endmethod.

method read_ref_key_list_accheader.

"entity type specific data types
data: ls_accheader_key_data type gty_cds_views-accheader,
lt_accitem_key_data type standard table of gty_cds_views-accitem,
ls_todo_list type /iwbep/if_v4_requ_basic_ref_l=>ty_s_todo_list.
"generic data types
data: ls_done_list type /iwbep/if_v4_requ_basic_ref_l=>ty_s_todo_process_list,
lv_nav_property_name type /iwbep/if_v4_med_element=>ty_e_med_internal_name.

" Get the request options the application should/must handle
io_request->get_todos( importing es_todo_list = ls_todo_list ).

if ls_todo_list-process-source_key_data = abap_true.
io_request->get_source_key_data( importing es_source_key_data = ls_accheader_key_data ).
ls_done_list-source_key_data = abap_true.
endif.

io_request->get_navigation_prop( importing ev_navigation_prop_name = lv_nav_property_name ).

case lv_nav_property_name.
when gcs_nav_prop_names-internal-accheader_to_items.

select opbel, OPUPW from zfica_dfkkop
into corresponding fields of table @lt_accitem_key_data
where opbel = @ls_accheader_key_data-opbel.

io_response->set_target_key_data( lt_accitem_key_data ).

when others.

endcase.

" Report list of request options handled by application
io_response->set_is_done( ls_done_list ).

endmethod.


method read_list_accheader.

"entity type specific data types
data : lt_key_range_accheader type zif_dfkkop_odata_v4_types=>gt_key_range-opbel,
ls_key_range_accheader type line of zif_dfkkop_odata_v4_types=>gt_key_range-opbel,
lt_accheader type standard table of gty_cds_views-accheader,
lt_key_accheader type standard table of gty_cds_views-accheader.

"generic data types
data: ls_todo_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_list,
ls_done_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_process_list,
lv_count type i,
lv_max_index type i.

" Get the request options the application should/must handle
io_request->get_todos( importing es_todo_list = ls_todo_list ).

" Get the request options the application has already handled
ls_done_list = is_done_list.


" specific sales orders based on navigation?
if ls_todo_list-process-key_data = abap_true.
io_request->get_key_data( importing et_key_data = lt_key_accheader ).
loop at lt_key_accheader into data(ls_key_entity).
append value #( sign = 'I' option = 'EQ' low = ls_key_entity-opbel ) to lt_key_range_accheader.
endloop.
ls_done_list-key_data = abap_true.
endif.


"================================================================
" read_list must either be called with a filter or via navigation
" or $top has to be used to avoid a full table scan
if ls_todo_list-process-filter = abap_false
and ls_todo_list-process-key_data = abap_false
and iv_top = 0.
endif.

" Return business data if requested
if ls_todo_list-return-busi_data = abap_true.

" read data from the CDS view
"value for max_index must only be calculated if the request also contains a $top
if iv_top is not initial.
lv_max_index = iv_top + iv_skip.
else.
lv_max_index = 0.
endif.

select (iv_select_string) from zfica_dfkkko
where (iv_where_clause)
and opbel in @lt_key_range_accheader
order by (iv_orderby_string)
into corresponding fields of table @lt_accheader
up to @lv_max_index rows.

"skipping entries specified by $skip
"not needed as of NW751 where OFFSET is supported in Open SQL
if iv_skip is not initial.
delete lt_accheader to iv_skip.
endif.

io_response->set_busi_data( it_busi_data = lt_accheader ).

else.
"if business data is requested count will be calculated by
"the framework
if ls_todo_list-return-count = abap_true.

select count( * ) from zfica_dfkkko
where (iv_where_clause) and
opbel in @lt_key_range_accheader
into @lv_count.

io_response->set_count( lv_count ).
endif.
endif.

" Report list of request options handled by application
io_response->set_is_done( ls_done_list ).
endmethod.

method read_list_accitem.

"entity type specific data types
data : lt_key_range_accheader type zif_dfkkop_odata_v4_types=>gt_key_range-opbel,
ls_key_range_accheadder type line of zif_dfkkop_odata_v4_types=>gt_key_range-opbel,
lt_key_range_accitem type zif_dfkkop_odata_v4_types=>gt_key_range-opupw,
ls_key_range_accitem type line of zif_dfkkop_odata_v4_types=>gt_key_range-opupw,
lt_accitem type standard table of gty_cds_views-accitem,
lt_key_accitem type standard table of gty_cds_views-accitem.

"generic data types
data: ls_todo_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_list,
ls_done_list type /iwbep/if_v4_requ_basic_list=>ty_s_todo_process_list,
lv_count type i,
lv_max_index type i.

" Get the request options the application should/must handle
io_request->get_todos( importing es_todo_list = ls_todo_list ).

" Get the request options the application has already handled
ls_done_list = is_done_list.

" specific sales orders based on navigation?
if ls_todo_list-process-key_data = abap_true.
io_request->get_key_data( importing et_key_data = lt_key_accitem ).
loop at lt_key_accitem into data(ls_key_entity).
append value #( sign = 'I' option = 'EQ' low = ls_key_entity-opbel ) to lt_key_range_accheader.
append value #( sign = 'I' option = 'EQ' low = ls_key_entity-opupw ) to lt_key_range_accitem.
endloop.

"the first key field (salesoder) is always the same
delete adjacent duplicates from lt_key_range_accheader.
ls_done_list-key_data = abap_true.
endif.


"================================================================
" read_list must either be called with a filter or via navigation
" or $top has to be used to avoid a full table scan
if ls_todo_list-process-filter = abap_false
and ls_todo_list-process-key_data = abap_false
and iv_top = 0.
endif.

" Return business data if requested
if ls_todo_list-return-busi_data = abap_true.

"value for max_index must only be calculated if the request also contains a $top
if iv_top is not initial.
lv_max_index = iv_top + iv_skip.
else.
lv_max_index = 0.
endif.

select (iv_select_string) from zfica_dfkkop
where (iv_where_clause)
and opbel in @lt_key_range_accheader
and opupw in @lt_key_range_accitem
order by (iv_orderby_string)
into corresponding fields of table @lt_accitem
up to @lv_max_index rows.


"skipping entries specified by $skip
"not needed as of NW751 where OFFSET is supported in Open SQL
if iv_skip is not initial.
delete lt_accitem to iv_skip.
endif.

io_response->set_busi_data( it_busi_data = lt_accitem ).

else.
"if business data is requested count will be calculated by
"the framework
if ls_todo_list-return-count = abap_true.

select count( * ) from zfica_dfkkop
where (iv_where_clause)
and opbel in @lt_key_range_accheader
and opupw in @lt_key_range_accitem
into @lv_count.

io_response->set_count( lv_count ).
endif.
endif.

" Report list of request options handled by application
io_response->set_is_done( ls_done_list ).

endmethod.
ENDCLASS.

5. Final project Structure in your Eclipse should be like this.

  • CDS Views





  • Classes





  • Interface



6. We are done with coding part. Now, we must register our OData V4 service using the TCode: /iwbep/v4_admin – Backend System.

6.1 Register a service group ZSG_DKKKOP.


 6.2 Register the service as shown below by giving created Model and Data Provider classes.


6.3 Assign service to our service group as shown below.


6.4 Publish the service group using transaction /iwfnd/v4_admin – (Gateway System)



7. Display Metadata in Browser and you can test the service using the Service Test option.



8. Test the service using POSTMAN.

/sap/opu/odata4/sap/zsg_dkkkop/default/sap/zsid_dfkkop/0001/AccHeader('100000000')?$expand=_Item


 

I'm sure, this blog will be useful to all the beginners who are going to start developing OData services in V4 🙂 . If anyone have suggestion on OData V4, please comment on it.

 

To find out the difference between OData V2 and V4. Please go through the following Blog.

https://blogs.sap.com/2021/02/05/is-it-time-to-switch-to-odata-v4/

Reference Blog:

https://blogs.sap.com/2017/12/12/odata-v4-code-based-implementation-overview/

 

Thank you,

Gangadhar
2 Comments
Labels in this area