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. An earlier post, External Numbering and Managed Early Numbering covers the details of the options available for Numbering.
This post talks about Unmanaged Early Numbering.
Unmanaged Early Numbering
This scenario is also referred to as ‘Unmanaged Internal Early Numbering’. In unmanaged BOs, the CREATE operation implements the assignment of a primary key value during the CREATE modification. If we have specified early numbering, a method implemented FOR NUMBERING
is triggered before the create method to handle the numbering.
Database Table
Persistent Table – zjp_carrier_uen
@EndUserText.label : 'Unmanaged Early Numbering (UEN)'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zjp_carrier_uen {
key client : abap.clnt not null;
key cuuid : sysuuid_x16 not null;
carrier_id : /dmo/carrier_id;
name : /dmo/carrier_name;
last_changed_at : abp_lastchange_tstmpl;
}
Draft table – zjp_carrier_uend
@EndUserText.label : 'Unmanaged Early Numbering (UEN) Draft Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zjp_carrier_uend {
key client : abap.clnt not null;
key cuuid : sysuuid_x16 not null;
carrierid : /dmo/carrier_id;
name : /dmo/carrier_name;
lastchangedat : abp_lastchange_tstmpl;
"%admin" : include sych_bdl_draft_admin_inc;
}
CDS View Entities
Root view entity – Z_I_CARRIER_UEN
@EndUserText.label: 'Carrier UEN Example'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define root view entity Z_I_CARRIER_UEN
as select from zjp_carrier_uen
{
key cuuid as Cuuid,
carrier_id as CarrierId,
name as Name,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}
Projection Entity – Z_C_CARRIER_UEN
Here, the annotations are added in the projection entity itself, but it is also possible to create metadata extensions.
@EndUserText.label: 'Carrier UEN Example'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@ObjectModel.semanticKey: [ 'CarrierId' ]
@UI: {
headerInfo: {
typeName: 'Carrier',
typeNamePlural: 'Carrier',
title: {
type: #STANDARD, value: 'Name'
},
description: {
value: 'CarrierID'
}
}
}
define root view entity Z_C_CARRIER_UEN
as projection on Z_I_CARRIER_UEN
{
@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 Cuuid,
@UI.lineItem: [{ position: 20 }]
@UI.identification: [{ position: 20 }]
CarrierId,
@UI.lineItem: [{ position: 30 }]
Name,
@UI.lineItem: [{ position: 40 }]
@UI.identification: [{ position: 30 }]
@UI.hidden: true
LastChangedAt
}
Behavior Definition
Unmanaged Behavior Definition – Z_I_CARRIER_UEN
Note that early numbering in unmanaged needs to be implemented with the draft.
unmanaged implementation in class zbp_i_carrier_uen unique;
strict ( 2 );
with draft;
define behavior for Z_I_CARRIER_UEN alias Carrier
early numbering
draft table zjp_carrier_uend
lock master
total etag LastChangedAt
authorization master ( instance )
{
field ( mandatory ) CarrierId, Name;
field ( readonly ) cUUID, LastChangedAt;
create;
update;
delete;
draft action Edit;
draft action Activate;
draft action Discard;
draft action Resume;
draft determine action Prepare;
mapping for zjp_carrier_uen control zjp_x_carrier corresponding
{
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_UEN 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 fix feature.
Class is generated. No code is implemented at this point. We will first generate the service, test the display and then start implementing the code.
Service Definition and Service Binding
Service Definition – ZSD_CARRIER_UEN
@EndUserText.label: 'Unmanaged Early Numbering'
define service ZSD_CARRIER_UEN {
expose Z_C_CARRIER_UEN as Carrier;
}
Service Binding – ZSB_CARRIER_UEN
Activate the service binding, and publish the service. Preview and service and ensure that the display part is working.
Sometimes, we may get the below error.
Application could not be started due to technical issues. Service group ‘ZSB_CARRIER_UEN’ not published. In this case, we may have to wait for some time and then try again.
The preview will be displayed
This gets the base service ready for us to implement.
Create a message class with a message for error handling.
Implement Numbering Method: earlynumbering_create FOR NUMBERING
The goal of the method code is to set keys for the entities and to fill either mapped-entity or failed-entity depending on whether the numbering is successful or failed.
METHOD earlynumbering_create.
"Keep only the entities that do not have the key
DATA(entities_wo_id) = entities.
DELETE entities_wo_id WHERE cuuid IS NOT INITIAL.
DATA(lo_uuid) = cl_uuid_factory=>create_system_uuid( ).
LOOP AT entities_wo_id INTO DATA(ls_entity).
TRY.
"Generate UUID. Here, number range FM can be called
ls_entity-cuuid = lo_uuid->create_uuid_c32( ).
"Add entity to mapped entity, note the draft key
APPEND VALUE #( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
) TO mapped-carrier.
CATCH cx_uuid_error INTO DATA(lx_uuid_error).
"In case of error, append to reported and failed
APPEND VALUE #( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
%msg = new_message(
id = 'ZJP_MSG'
number = '001'
severity = if_abap_behv_message=>severity-error )
) TO reported-carrier.
APPEND VALUE #( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
) TO failed-carrier.
ENDTRY.
ENDLOOP.
ENDMETHOD.
Test the application for Numbering
When create is clicked, the key field UUID is filled, and create screen appears.
At this point, the create/save would not work. For that, we would need to implement the create
and save
methods as well. The way RAP BO works is the INSERT/UPDATE/DELETE
statements can be written only in the saver class, so we need to create a helper class to pass data from the create method to the save method.
ZCL_CARRIER_GLOBAL
This class has a method to create an instance, another method to create a carrier which stores the carriers to be created as a private data table, and then
CLASS zcl_carrier_global DEFINITION
PUBLIC
FINAL
CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS: get_instance RETURNING VALUE(ro_instance) TYPE REF TO zcl_carrier_global.
METHODS : create_carrier IMPORTING is_carrier TYPE zjp_carrier_uen,
save,
initialize.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-DATA go_instance TYPE REF TO zcl_carrier_global.
"Buffer tables to save data
DATA : gt_carrier TYPE STANDARD TABLE OF zjp_carrier_uen.
ENDCLASS.
CLASS zcl_carrier_global 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.
ENDMETHOD.
METHOD initialize.
CLEAR gt_carrier.
ENDMETHOD.
METHOD save.
INSERT zjp_carrier_uen FROM TABLE @gt_carrier.
initialize( ).
ENDMETHOD.
ENDCLASS.
Create
DATA : ls_carrier TYPE zjp_carrier_uen,
lt_carrier TYPE STANDARD TABLE OF zjp_carrier_uen.
LOOP AT entities INTO DATA(ls_entity).
DATA(lo_carrier) = zcl_carrier_global=>get_instance( ).
ls_carrier = CORRESPONDING #( ls_entity MAPPING FROM ENTITY USING CONTROL ).
"Implement Validations and field determinations - here, numbers are not allowed
IF ls_carrier-carrier_id CA '0123456789'.
failed-carrier = VALUE #( BASE failed-carrier
( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
)
).
reported-carrier = VALUE #( BASE reported-carrier
( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
%msg = new_message(
id = 'ZJP_MSG'
number = '003'
severity = if_abap_behv_message=>severity-error )
)
).
ELSE.
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
cuuid = ls_entity-cuuid )
).
ENDIF.
ENDLOOP.
Save
METHOD save.
DATA(lo_carrier) = zcl_carrier_global=>get_instance( ).
lo_carrier->save( ).
ENDMETHOD.
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_UEN
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 earlynumbering_create FOR NUMBERING
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_uen,
lt_carrier TYPE STANDARD TABLE OF zjp_carrier_uen.
LOOP AT entities INTO DATA(ls_entity).
DATA(lo_carrier) = zcl_carrier_global=>get_instance( ).
ls_carrier = CORRESPONDING #( ls_entity MAPPING FROM ENTITY USING CONTROL ).
"Implement Validations and field determinations
IF ls_carrier-carrier_id CA '0123456789'.
failed-carrier = VALUE #( BASE failed-carrier
( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
)
).
reported-carrier = VALUE #( BASE reported-carrier
( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
%msg = new_message(
id = 'ZJP_MSG'
number = '003'
severity = if_abap_behv_message=>severity-error )
)
).
ELSE.
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
cuuid = ls_entity-cuuid )
).
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD earlynumbering_create.
DATA(entities_wo_id) = entities.
DELETE entities_wo_id WHERE cuuid IS NOT INITIAL.
LOOP AT entities_wo_id INTO DATA(ls_entity).
DATA(lo_uuid) = cl_uuid_factory=>create_system_uuid( ).
TRY.
ls_entity-cuuid = lo_uuid->create_uuid_c32( ).
APPEND VALUE #( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
) TO mapped-carrier.
CATCH cx_uuid_error INTO DATA(lx_uuid_error).
APPEND VALUE #( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
%msg = new_message(
id = 'ZJP_MSG'
number = '001'
severity = if_abap_behv_message=>severity-error )
) TO reported-carrier.
APPEND VALUE #( %cid = ls_entity-%cid
%key = ls_entity-%key
%is_draft = ls_entity-%is_draft
) TO failed-carrier.
ENDTRY.
ENDLOOP.
ENDMETHOD.
METHOD update.
ENDMETHOD.
METHOD delete.
ENDMETHOD.
METHOD read.
ENDMETHOD.
METHOD lock.
ENDMETHOD.
ENDCLASS.
CLASS lsc_z_i_carrier_uen DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS save REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
CLASS lsc_z_i_carrier_uen IMPLEMENTATION.
METHOD finalize.
ENDMETHOD.
METHOD check_before_save.
ENDMETHOD.
METHOD save.
DATA(lo_carrier) = zcl_carrier_global=>get_instance( ).
lo_carrier->save( ).
ENDMETHOD.
METHOD cleanup.
ENDMETHOD.
METHOD cleanup_finalize.
ENDMETHOD.
ENDCLASS.
Test Create end to end
When a numeric id is entered, the application throws an error.
Change the id to match the validation.
Click on create.
The object is created and can be also seen on the list page.
Also read: Unmanaged Late Numbering
References:
Visit ABAP RESTful Application Programming Model to explore all articles on ABAP RAP Model.
If you like the content, please subscribe…