Numbering in ABAP RESTful Application Programming means setting up values for the primary key fields of the entity. The primary key can consist of one or more fields.
Earlier posts cover
- the details of the options available for Numberin – External Numbering and Managed Early Numbering
- Unmanaged Early Numbering
This post talks about Unmanaged Late Numbering.
Unmanaged Late Numbering
This scenario is also referred to as ‘Unmanaged Internal Late Numbering’. This scenario is useful for a gapless assignment of unique keys.
Internal late numbering means:
- The RAP runtime engine assigns values to the primary key fields.
- The RAP saver method
adjust_numbers
must be implemented to assign a final primary key value. - The key value for an instance is assigned just before the instance is saved on the database.
Note that this posts explains how the methods can be utilized and more research is required for implementation of actual project like scenario.
Database table & structure
Persistent Table – zjp_carrier_uln
@EndUserText.label : 'Unmanaged Late Numbering (ULN)'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zjp_carrier_uln {
key client : abap.clnt not null;
key intid : abap.int4 not null;
carrier_id : /dmo/carrier_id;
name : /dmo/carrier_name;
last_changed_at : abp_lastchange_tstmpl;
}
Draft table – zjp_d_carr_uln
@EndUserText.label : 'Unmanaged Late Numbering (ULN) Draft Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zjp_d_carr_uln {
key client : abap.clnt not null;
key intid : abap.int4 not null;
key draftuuid : sysuuid_x16 not null;
carrierid : /dmo/carrier_id;
name : /dmo/carrier_name;
lastchangedat : abp_lastchange_tstmpl;
"%admin" : include sych_bdl_draft_admin_inc;
}
Control Structure – ZJP_ULN_CARRIER
@EndUserText.label : 'ULN Carrier'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
define structure zjp_uln_carrier {
int_id : xsdboolean;
carrier_id : xsdboolean;
name : xsdboolean;
last_changed_at : xsdboolean;
}
CDS View Entities
Root view entity – Z_I_CARRIER_ULN
@EndUserText.label: 'Carrier ULN Example'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define root view entity Z_I_CARRIER_ULN
as select from zjp_carrier_uln
{
key intid as IntId,
carrier_id as CarrierId,
name as Name,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}
Projection Entity – Z_C_CARRIER_ULN
Here, the annotations are added in the projection entity itself, but it is also possible to create metadata extensions.
@EndUserText.label: 'Carrier ULN Example'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@ObjectModel.semanticKey: [ 'IntId' ]
@UI: {
headerInfo: {
typeName: 'Carrier',
typeNamePlural: 'Carrier'
}
}
define root view entity Z_C_CARRIER_ULN
as projection on Z_I_CARRIER_ULN
{
@UI.facet:
[ {
label: 'Carrier Details',
id: 'CarrierInfo',
type: #COLLECTION,
position: 10
},
{
label: 'Carrier',
id: 'Carrier',
type: #IDENTIFICATION_REFERENCE,
purpose: #STANDARD,
parentId: 'CarrierInfo',
position: 10
} ]
@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
key IntId,
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]
CarrierId,
@UI.lineItem: [{ position: 30 }]
@UI.identification: [{ position: 30 }]
Name,
@UI.hidden: true
LastChangedAt
}
Behavior Definition
Unmanaged Behavior Definition – Z_I_CARRIER_ULN

The late numbering in unmanaged can be implemented with or without a draft. This example considers a scenario with the draft as the V4 service will show create button only with draft functionality.
unmanaged implementation in class zbp_i_carrier_uln unique;
strict ( 2 );
with draft;
define behavior for Z_I_CARRIER_ULN alias Carrier
late numbering
draft table zjp_d_carr_uln
lock master
total etag LastChangedAt
authorization master ( instance )
{
field ( mandatory ) CarrierId, Name;
field ( readonly ) IntId, LastChangedAt;
create;
update;
delete;
draft action Edit;
draft action Activate;
draft action Discard;
draft action Resume;
draft determine action Prepare;
mapping for zjp_carrier_uln control zjp_uln_carrier corresponding
{
IntId = intid;
CarrierId = carrier_id;
Name = name;
LastChangedAt = last_changed_at;
}
}
Create the projection behavior definition.

projection;
strict ( 2 );
use draft;
define behavior for Z_C_CARRIER_ULN alias Carrier
{
use create;
use update;
use delete;
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;
}
Implementation Class
Create the class using the quick assist feature.

Class is generated. No code is implemented at this point. We will first generate the service, test the display, and implement the code.

Service Definition and Service Binding
Service Definition – ZSD_CARRIER_ULN
@EndUserText.label: 'Unmanaged Late Numbering'
define service ZSD_CARRIER_ULN {
expose Z_C_CARRIER_ULN as Carrier;
}
Service Binding – ZSB_CARRIER_ULN

Activate the service binding, and publish the service. Preview and service and ensure that the display part is working.
The preview will be displayed

This gets the base service ready for us to implement.
Support Class to save data buffer – zcl_carrier_uln
CLASS zcl_carrier_uln DEFINITION
PUBLIC
FINAL
CREATE PRIVATE.
PUBLIC SECTION.
TYPES : tty_carriers TYPE STANDARD TABLE OF zjp_carrier_uln WITH EMPTY KEY.
CLASS-METHODS: get_instance RETURNING VALUE(ro_instance) TYPE REF TO zcl_carrier_uln.
METHODS : create_carrier IMPORTING is_carrier TYPE zjp_carrier_uln,
adjust_number RETURNING VALUE(rt_carriers) TYPE tty_carriers,
save,
initialize.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-DATA go_instance TYPE REF TO zcl_carrier_uln.
"Buffer tables to save data
DATA : gt_carrier_create TYPE STANDARD TABLE OF zjp_carrier_uln.
ENDCLASS.
CLASS zcl_carrier_uln IMPLEMENTATION.
METHOD get_instance.
go_instance = COND #( WHEN go_instance IS BOUND THEN go_instance ELSE NEW #( ) ).
ro_instance = go_instance.
ENDMETHOD.
METHOD create_carrier.
APPEND is_carrier TO gt_carrier_create.
ENDMETHOD.
METHOD adjust_number.
"Number range object can be called here
"For demo, highest number from table is used
SELECT MAX( intid )
FROM zjp_carrier_uln
INTO @DATA(lv_max_id).
LOOP AT gt_carrier_create ASSIGNING FIELD-SYMBOL(<lfs_carr>).
lv_max_id += 1.
<lfs_carr>-intid = lv_max_id.
ENDLOOP.
rt_carriers = gt_carrier_create.
ENDMETHOD.
METHOD initialize.
CLEAR gt_carrier_create.
ENDMETHOD.
METHOD save.
INSERT zjp_carrier_uln FROM TABLE @gt_carrier_create.
initialize( ).
ENDMETHOD.
ENDCLASS.
Implement unmanaged create
METHOD create.
DATA : ls_carrier TYPE zjp_carrier_uln.
LOOP AT entities INTO DATA(ls_entity).
DATA(lo_carrier) = zcl_carrier_uln=>get_instance( ).
ls_carrier = CORRESPONDING #( ls_entity MAPPING FROM ENTITY USING CONTROL ).
"Implement Validations and field determinations here - if needed
lo_carrier->create_carrier( ls_carrier ).
mapped-carrier = VALUE #( BASE mapped-carrier
( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
) ).
ENDLOOP.
ENDMETHOD.
Implement Numbering Method: adjust_numbers
For late numbering, the method adjust_numbers
is implemented in the behavior-saver class.

The goal of the method code is to determine key values, set the keys and then fill mapped-entity. As the actual numbering logic is implemented in the helper class – this code looks simpler.
METHOD adjust_numbers.
DATA(lo_carrier) = zcl_carrier_uln=>get_instance( ).
data(lt_carriers) = lo_carrier->adjust_number( ).
mapped-carrier = VALUE #( for ls_carrier in lt_carriers
( intid = ls_carrier-intid )
).
ENDMETHOD.
Implement Save method
METHOD save.
DATA(lo_carrier) = zcl_carrier_uln=>get_instance( ).
lo_carrier->save( ).
ENDMETHOD.
Test the application for Numbering
When create is clicked, the key field is 0.
Similarly, update and delete operations can be implemented using separate buffer tables for create, update, and delete.
For reference, the complete class code is as below.
ZBP_I_CARRIER_ULN
CLASS lhc_carrier DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR carrier RESULT result.
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE carrier.
METHODS update FOR MODIFY
IMPORTING entities FOR UPDATE carrier.
METHODS delete FOR MODIFY
IMPORTING keys FOR DELETE carrier.
METHODS read FOR READ
IMPORTING keys FOR READ carrier RESULT result.
METHODS lock FOR LOCK
IMPORTING keys FOR LOCK carrier.
ENDCLASS.
CLASS lhc_carrier IMPLEMENTATION.
METHOD get_instance_authorizations.
ENDMETHOD.
METHOD create.
DATA : ls_carrier TYPE zjp_carrier_uln.
LOOP AT entities INTO DATA(ls_entity).
DATA(lo_carrier) = zcl_carrier_uln=>get_instance( ).
ls_carrier = CORRESPONDING #( ls_entity MAPPING FROM ENTITY USING CONTROL ).
"Implement Validations and field determinations here - if needed
lo_carrier->create_carrier( ls_carrier ).
mapped-carrier = VALUE #( BASE mapped-carrier
( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
) ).
ENDLOOP.
ENDMETHOD.
METHOD update.
ENDMETHOD.
METHOD delete.
ENDMETHOD.
METHOD read.
ENDMETHOD.
METHOD lock.
ENDMETHOD.
ENDCLASS.
CLASS lsc_z_i_carrier_uln DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS adjust_numbers REDEFINITION.
METHODS save REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
CLASS lsc_z_i_carrier_uln IMPLEMENTATION.
METHOD finalize.
ENDMETHOD.
METHOD check_before_save.
ENDMETHOD.
METHOD adjust_numbers.
DATA(lo_carrier) = zcl_carrier_uln=>get_instance( ).
data(lt_carriers) = lo_carrier->adjust_number( ).
mapped-carrier = VALUE #( for ls_carrier in lt_carriers
( intid = ls_carrier-intid )
).
ENDMETHOD.
METHOD save.
DATA(lo_carrier) = zcl_carrier_uln=>get_instance( ).
lo_carrier->save( ).
ENDMETHOD.
METHOD cleanup.
ENDMETHOD.
METHOD cleanup_finalize.
ENDMETHOD.
ENDCLASS.
Test the application

Create a new carrier.

After creation, the key is visible.

Also read:
References:
Visit ABAP RESTful Application Programming Model to explore all articles on ABAP RAP Model.
If you like the content, please subscribe…