How to use Early Numbering with Semantic Keys – RAP Managed BO

In my previous blog post, I discussed how to use Late Numbering in RAP Unmanaged Business Object.

If you are new to RESTful Application Programming (RAP) model, then this blog post by Carine Tchoutouo Djomo is a great starting place.

For this post, I assume you have some knowledge of RAP, Core Data Services (CDS) views and so on.

Source code for all artifacts including tables and CDS views are available in this GitHub repository.

Early Numbering – Managed & Unmanaged

Early numbering is a scenario in which instance keys are generated in the interaction phase of RAP as opposed to Late Numbering where keys are generated during save phase.

If your Business Object has GUID based keys, then you can use managed early numbering. It is managed because RAP runtime engine generates and assigns values to primary key fields.

In this post, I am going to discuss unmanaged early numbering.  It is unmanaged because:

  • RAP runtime engine assigns values to primary key fields
  • How this assignment takes place is defined by the application developer in the behavior implementation pool inside specially defined methods for this purpose.  Such methods are defined using keywords FOR NUMBERING

Demo Business Object – the “Document”

This demo business object, called the “Document”, named so for the lack of any kind of creativity on my part, has 3 tables:


Tables and Foreign Key Relationships

Here are the CDS view entities where ZDH_MngdDocumentHeader is the root entity:


CDS Model

Initial Behavior Definition (BDEF) (Managed)

When you generate the BDEF, it would look like this initially:


Initial Behavior Definition as generate

Let’s add some more details to this BDEF such as “alias” for each entity, authorization, etag and lock.

Define Unmanaged Early Numbering

This is done by adding the keywords early numbering for each entity that needs to implement this.  Notice the highlighted lines in the BDEF below:


Behavior Definition Updated

Since, field names in tables and respective CDS views are different, you also need to add mapping for each entity.  It looks like something like below.  Refer to GitHub folder for complete listing.  This is not required for early numbering, per se.


Field Mapping

Activate BDEF and then use quick help to generate the BIL class.  It should look something like this:


Initial Behavior Implementation Class

Notice the highlighted methods – for each entity that has early numbering defined, there is a method generated. Notice the FOR NUMBERING in the method definition.

These methods are called when instances of those entities are “created”.  In other words when you execute MODIFY ENTITIES OF... CREATE...  or MODIFY ENTITIES OF.... CREATE BY... for an entity, respective FOR NUMBERING method is called.

Our goal is to add some lines of code here to generate the keys for each entity instances.

Pause and Note

This post is for educational purpose only.  It is to demonstrate “how” to implement early numbering. Therefore, numbers are generated in a very simplistic manner.  In a productive implementation, you will want to draw these numbers from Number Range object.  How to do that is not in the scope of this post.

Also, note that, when keys are generated early in the interaction phase, validation failures in the later phase may cause gaps in the numbering.  Therefore, if gap-less numbering is important or numbers need to be sequential, take extra caution while using this method!

Generate keys

I created this class ZCL_DH_MNGD_DOCUMENT_HANDLER which has 3 methods:

  • GET_NEXT_DOC_NUMBER -> returns next available document number. How it is done is not so important
  • GET_NEXT_ITEM_NUMBER -> returns next item number for a given document
  • GET_NEXT_ACCOUNT_NUMBER -> returns next account number for a given document item

Implement Numbering methods in BIL

In EARLYNUMBERING_ methods of BIL class, for each created instance (%CID), generate a new number and then fill “mapped” parameter.

These methods are called before any determination ... on modify { create; } are called

In EARLYNUMBERING_CREATE method, notice that we are filling MAPPED-HEADER by calling GET_NEXT_DOC_NUMBER() method:

 METHOD earlynumbering_create. DATA(lo_doc_handler) = zcl_dh_mngd_document_handler=>get_instance( ). LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>). INSERT VALUE #( %cid = <ls_entity>-%cid DocumentNumber = lo_doc_handler->get_next_doc_number( ) ) INTO TABLE mapped-header. ENDLOOP. ENDMETHOD.

In EARLYNUMBERING_CBA_ITEM method, we are filling MAPPED-ITEM by calling GET_NEXT_ITEM_NUMBER() method.  Notice that we are passing the DocumentNumber to this method which is available in the importing parameter entities:

METHOD earlynumbering_cba_Item. DATA(lo_doc_handler) = zcl_dh_mngd_document_handler=>get_instance( ). LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>). LOOP AT <ls_entity>-%target ASSIGNING FIELD-SYMBOL(<ls_item_create>). INSERT VALUE #( %cid = <ls_item_create>-%cid DocumentNumber = <ls_entity>-DocumentNumber ItemNumber = lo_doc_handler->get_next_item_number( iv_doc_number = <ls_entity>-DocumentNumber ) ) INTO TABLE mapped-item. ENDLOOP. ENDLOOP. ENDMETHOD.

Similar logic is implemented in method EARLYNUMBERING_CBA_ACCOUNT as well.

 METHOD earlynumbering_cba_Account. DATA(lo_doc_handler) = zcl_dh_mngd_document_handler=>get_instance( ). LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>). LOOP AT <ls_entity>-%target ASSIGNING FIELD-SYMBOL(<ls_account_create>). INSERT VALUE #( %cid = <ls_account_create>-%cid DocumentNumber = <ls_entity>-DocumentNumber ItemNumber = <ls_entity>-ItemNumber AccountNumber = lo_doc_handler->get_next_account_number( iv_doc_number = <ls_entity>-DocumentNumber iv_item_number = <ls_entity>-ItemNumber ) ) INTO TABLE mapped-account. ENDLOOP. ENDLOOP. ENDMETHOD.

Apart from this, we have also added a determination for each entity in our BDEF named Defaults to fill administrative fields such as CreatedBy, CreatedOn.  Complete listing of BIL class as well as ZCL_DH_MNGD_DOCUMENT_HANDLER is available on the GitHub repo.

EML Test – Deep Create:

Let’s test it by writing an EML test.

Below EML will create 1 document with 1 item and 1 account line. Use valid company code, purchase organization and cost center depending on in which system you are writing this:

MODIFY ENTITIES OF ZDH_MngdDocumentHeader ENTITY Header CREATE SET FIELDS WITH VALUE #( ( %cid = 'doc1' CompanyCode = '0001' PurchasingOrganization = '0001' ) ) CREATE BY \_Item SET FIELDS WITH VALUE #( ( %cid_ref = 'doc1' %target = VALUE #( ( %cid = 'item1' itemdescription = 'EML Test Item 1' ) ) ) ) ENTITY Item CREATE BY \_Account SET FIELDS WITH VALUE #( ( %cid_ref = 'item1' %target = VALUE #( ( %cid = 'acc1' costcenter = 'SVC_001' ) ) ) ) MAPPED DATA(mapped) FAILED DATA(failed) REPORTED DATA(reported). COMMIT ENTITIES.

You can find complete test implemented as A Unit on GitHub repo.  This listing should go into “local test classes” of our BIL class.


  • Define early numbering in BDEF for each entity where you need to generate and assign primary keys
  • Implement a method FOR NUMBERING for each such entity
  • Methods should map “%CID”s to generated number and fill respective  mappedparameter

That’s it for this post.  I hope this was helpful.  Let me know in the comments how I could improve this post.