Enabling and Developing Behavior Extensions

Objectives

After completing this lesson, you will be able to:
  • Enable behavior extensions.
  • Extend the behavior of a business object.

Extensibility Enablement for Behavior Definitions

A visual representation of behavior definition extension

CDS behavior definitions are extended with CDS behavior extensions. It is possible to create behavior extensions on data model level and on projection level. The creation of behavior extensions on interface level, however, is not supported. The behavior of BO interfaces is always extended indirectly through the behavior extension of the underlying business object definition.

The developer in charge of a behavior definition, projection, or interface is able to control whether behavior extensions can be created and to what extend the behavior can be extended.

Because A BO interface cannot be extended directly, the extensions always refer to the underlying base business object but uses the using interface addition to refer to the interface as well.

The EXTENSIBLE addition in behavior definitions

Behavior extensibility is controlled by adding the extensible addition to the behavior definition. The extensible addition is only supported in strict mode, that is, if the behavior definition contains either the strict; or the strict( 2 ); directive.

The addition is supported in the following places:

Behavior Definition Header

Adding extensible in the behavior definition header is a prerequisite for adding it anywhere else in the behavior definition. If specified, at least one RAP BO entity must be declared as extensible in its entity behavior characteristics. Within curly brackets, one or more of the following additions are possible:

  • with validations on save
  • with determinations on save
  • with determinations on modify
  • with additional save

These additions explicitly allow validations, determinations, or an additional save in an entity behavior extension. If not declared explicitly, the respective type of determination, validation, or the additional save must not be defined in an extension to an existing RAP BO entity.

Entity Behavior Characteristics

Adding extensible to the define behavior for statement is mandatory for each BO entity that allows extensions. The addition allows the extension of the BO entity with actions, determine actions, and field characteristics for extension fields. The extension with determinations, validations, and an additional save depends on the extensible syntax in the behavior definition header.

Determine Action Definition

Adding extensible to a determine action statement allows validations and determinations to be added to the determine action in question. It is only supported in draft-enabled business objects.

Hint

If you enable the extension of a business object with validations and/or determinations on save, it is strongly recommended to define the draft determine action Prepare as extensible.

Field Mapping

By adding extensible to a mapping for statement, the field mapping can be extended with extension fields. The extensible addition can only be used with corresponding, so that components with the same name are automatically mapped to each other.

Hint

The moment you define a behavior definition extensible the syntax check issues a warning that tells you to make all field mappings extensible. However, it does not make much sense if the related persistent table or dictionary structure type is not extensible. You can suppress the warning using the ##UNEXTENSIBLE_MAPPING pragma.

The EXTENSIBLE addition in behavior projections and interfaces

On projection level, the use of the extensible addition is similar to its use on data model level. However, there are no curly brackets supported after the extensible keyword in the behavior definition header.

Note

For declaring a behavior projection as extensible, it is not necessary that the underlying behavior definition is declared as extensible. A behavior projection can be extensible independently of the projected business object.

In a behavior definition on interface level, the keyword extensible can only be specified in the behavior definition header. This specification includes all entities and components that are included in the interface.

Behavior Extensions

Steps to create a CDS behavior extension

To create a CDS behavior extension, proceed as follows:

  1. In the project explorer, locate the behavior definition that you want to extend.
  2. Right-click the behavior definition and choose New Behavior Extension.
  3. Adjust the package, enter a name and a description for the new object.

    Note

    Usually, the behavior extension does not lie in the same package as the target behavior definition. Therefore, it is important to adjust the suggested package.

  4. Confirm that the Behavior Definition field contains the name of the target behavior definition and choose Next.

    Note

    If you extend a behavior definition on data model level and want to also extend the related BO interface, enter the name of the BO interface in the respective field. If not, leave that field empty.

  5. Enter a transport request and choose Finish.
CHS extension behavior with the keyword extension in the header

CDS behavior extensions are recognizable by the extension keyword in the header. If the target behavior definition is on data model level, there is an implemented in class addition, followed by the name of a behavior pool for the extension implementation.

Note

Currently, a behavior pool is not supported if the target is a behavior definition on projection level.

If the extension on data model level is meant to extend the BO interface as well, the BO Interface name is specified after the using the interface addition.

The behavior of the BO entities is extended in relatedextend behavior for statements. If the target behavior definition defines entity alias names, it is recommended to address its entities using these alias names.

Note

Using the alias names becomes mandatory if the extension statement contains the using interface addition.

Example of extending a BO node with additional save and validation

The extend behavior for statement is similar to the define behavior for statement.

In the example, the behavior extension uses the with additional save addition to extend the root node of the business object with an additional save implementation.

In the behavior extension body, it uses the validation keyword to define an additional validation. If needed, it uses the determination and action keywords in a similar way.

Note

If the behavior extension lies in a different namespace than the target behavior definition, the syntax check enforces a namespace prefix for the new elements.

To extend a field mapping, the behavior extension uses the extend keyword followed by the normal definition syntax of the mapping. It results in the following syntax: extend mapping for … { }.

Similarly, it uses the extend keyword followed by the normal definition syntax of a determine action to extend a determine action.

In the example, the behavior extension extends the draft determine action Prepare with the following syntax: extend draft determine action Prepare { … }.

Example of extending a business object with an additional node

Besides the extend behavior for statements, a behavior extension can also contain define behavior for statements. These are used to extend the node hierarchy of a business object with additional nodes. The statement is followed by the name of a CDS view entity that defines the properties of the new node. If the behavior extension specifies a BO interface, the using addition is needed to specify the corresponding CDS view entity on interface level.

As usual, the association keyword is used to define the behavior for the to-parent association. The behavior for the corresponding composition is defined in the behavior extension of the existing parent node, for example the root node.

Note

The associations themselves are defined in the CDS view entity, either directly, in case of the to-parent association, or in a CDS view extension, in case of the composition.

Behavior Extension Implementation

Usage of quick fix to create the extension behavior pool

If the extension statement contains an implementation in class addition, you can use a quick fix as usual, to create the extension behavior pool.

The quick fix generates all local classes and methods that are needed to implement the behavior extension at this point. If you later change the behavior extension that requires extra implementation methods, similar quick fixes are available. For example, if you define another validation, you can use the usual quick fix to add the related method to the local handler class.

Enable and Develop Behavior Extensions

In this exercise, you enable the extension of the standard behavior of your business object for flight travels on both data model and projection level.

Then, you extend the behavior. First, you extend the flight travel items with an additional save implementation in which you persist the booking class field in the active table. Then, you add a validation for the booking class field.

Note

In this exercise, you extend your own business object. It is done for simplicity. To motivate the use of extensions, pretend that once you enabled the extension of the standard behavior, the behavior definitions Z##_R_TRAVEL and Z##_C_TRAVEL suddenly lie in a different namespace and that you are no longer authorized to make direct changes to these objects.

Note

In this exercise, replace ## with your group number.

Solution

Repository Object TypeRepository Object ID
CDS Behavior Definition (Model)/LRN/437H_R_TRAVEL
CDS Behavior Definition (Projection)/LRN/437H_C_TRAVEL
CDS Behavior Definition (Model Extension)/LRN/ZZX_R_TRAVEL_CLASS
CDS Behavior Definition (Projection Extension)/LRN/ZZX_C_TRAVEL_CLASS
ABAP Class (Extension Implementation)/LRN/BP_ZZX_R_TRAVEL_CLASS
  

Task 1: Enable Behavior Extension

Enable the behavior extension for your business object Z##_R_TRAVEL and both its entities. Allow the extension with extra validations and determinations (both execution times) and the extension with an additional save implementation. Make sure that it is possible to add the additional validations and determinations to the draft determine action Prepare.

Steps

  1. Open your behavior definition on data model level Z##_R_TRAVEL and enable it for extension.

    1. Insert the extensible addition as follows:

      Code Snippet
      123456789
      managed implementation in class zbp_##_r_travel unique; strict ( 2 ); with draft; extensible { }
  2. Use code completion to add all supported with additions.

    1. Place the cursor inside the curly brackets after the extensible keyword and press Ctrl + Space to invoke code completion.

    2. From the suggestion list, choose with additional save; (keyword).

    3. Repeat this, choosing all WITH additions until your code looks as follows:

      Code Snippet
      123456789101112
      managed implementation in class zbp_##_r_travel unique; strict ( 2 ); with draft; extensible { with additional save; with validations on save; with determinations on modify; with determinations on save; }
  3. Perform a syntax check.

    1. Press Ctrl + F2 to perform a syntax check.

    2. Analyze the Problems view below the editor.

  4. Enable the root entity and the child entity of the business object for extension, then repeat the syntax check.

    1. In the define behavior for Z##_R_Travel statement, add the extensible addition as follows:

      Code Snippet
      1234567891011
      define behavior for Z##_R_Travel alias Travel persistent table z##_travel ##UNMAPPED_FIELD draft table z##_travel_d lock master total etag ChangedAt authorization master ( instance ) etag master LocChangedAt early numbering with additional save extensible {
    2. In the define behavior for Z##_R_TravelItem statement, add the extensible addition as follows:

      Code Snippet
      12345678
      define behavior for Z##_R_TravelItem alias Item with unmanaged save draft table z##_tritem_d authorization dependent by _Travel lock dependent by _Travel etag master LocChangedAt extensible {
  5. Enable the draft determine action Prepare for extension and check that the corresponding syntax warning is gone.

    1. In the draft determine action Prepare statement, add the extensible addition as follows:

      Code Snippet
      123
      draft determine action Prepare extensible {
  6. Use a pragma to suppress the warnings on missing extensibility of the field mappings.

    Hint

    You find the relevant pragma in the Problem Description for the warning.

    Note

    Neither the persistent table for flight travels Z##_TRAVEL nor the structure /LRN/437_S_TRITEM are extensible. Therefore, extensibility of the mapping is not required. - The mapping for table Z##_TRITEM could even be deleted, since this table is no longer specified as persistent table and an unmanaged save implementation is used instead.
    1. In the Problems view, right-click the warning message and choose Problem Description. The name of the required pragma is UNEXTENSIBLE_MAPPING.

    2. In the three mapping for statements, add the ##UNEXTENSIBLE_MAPPING pragma as follows:

      Code Snippet
      12
      mapping for z##_travel corresponding ##unextensible_mapping {
      Code Snippet
      12
      mapping for z##_tritem corresponding ##unextensible_mapping {
      Code Snippet
      1234
      mapping for /lrn/437_s_tritem control /lrn/437_s_tritemx corresponding ##unextensible_mapping {
  7. Activate the behavior definition.

    1. Press Ctrl + F3 to activate the development object.

Task 2: Extend with Additional Save

Make sure the booking class field ZZClassZ## that you added to the flight travel items in an earlier exercise is written to the corresponding database table field ZZCLASSZ##. To do so, do not edit the behavior implementation directly. Instead, create a behavior extension for the flight travel business object (suggested name: Z##X_R_TRAVEL_CLASS) and implement an additional save logic in a behavior extension implementation class.

Note

In scenarios with managed save, it is sufficient to extend the field mapping to write the extension fields to the append fields in the database table. If the field names only differ in upper/lower case, and if the mapping statement comes with a corresponding addition, even that might not be necessary.

In our scenario, however, the flight travel items are written to the database in an unmanaged save implementation. Here, it would be necessary to add the new fields to the signature of the reused code, that is, the /LRN/437_S_TRITEM and /LRN/437_S_TRITEMX structures and then extend the field mapping. Because these structures are marked as not extensible, we have to extend the behavior with an additional save.

Steps

  1. For the behavior definition on data model level Z##_R_TRAVEL, create a new behavior extension (suggested name: Z##X_R_TRAVEL_CLASS).

    1. In the Project Explorer, expand Favorite Packages.

    2. Under your own package ZS4D437_##, expand Core Data ServicesBehavior Definitions.

    3. Right-click Z##_R_TRAVEL and select New Behavior Extension.

    4. Under Name, enter Z##X_R_TRAVEL_CLASS and under Description, enter Extend Travel Item with Booking Class. Choose Next.

      Note

      We did not create a BO Interface for our business object. Therefore, leave the BO Interface field empty.
    5. Assign the new development object to a transport request and choose Finish.

  2. Extend the child entity Item with an additional save definition.

    1. Adjust the code as follows:

      Code Snippet
      1234
      extend behavior for Item with additional save { }
  3. Activate the behavior extension.

    1. Press Ctrl + F3 to activate the development object.

  4. Use a quick fix to generate the extension implementation class (suggested name: ZBP_##X_R_TRAVEL_CLASS).

    1. In the extension implementation in class statement, place the cursor on zbp_##x_r_travel_class and press Ctrl + 1 to invoke the quick assist proposals. Alternatively, you can choose the warning icon with light bulb on the left of this code row.

    2. From the list of available quick fixes, choose Create behavior implementation class zbp_##x_r_travel_class.

    3. Confirm the package and description and choose Next.

    4. Assign the object to a transport request and choose Finish.

  5. Implement the save_modified method of the local class LSC_Z##_R_TRAVEL in the global class ZBP_##X_R_TRAVEL_CLASS. Assigning an inline declared field symbol, loop over the items that require an update of the booking class field.

    Note

    The items that require an update of the booking class have the value if_abap_behv=>mk-on in the %control-ZZClassZ## field.
    1. Adjust the code as follows:

      Code Snippet
      12345678
      METHOD save_modified. LOOP AT update-item ASSIGNING FIELD-SYMBOL(<item>) WHERE %control-ZZClassZ## = if_abap_behv=>mk-on. ENDLOOP. ENDMETHOD.
  6. Inside the loop, implement an ABAP SQL UPDATE statement for your database table for active travel items Z##_TRITEM to update the booking class field in the affected data set.

    Caution

    We recommend the UPDATE statement with the SET addition to make sure you do not overwrite any of the other fields.
    1. Adjust the code as follows:

      Code Snippet
      123456789101112
      METHOD save_modified. LOOP AT update-item ASSIGNING FIELD-SYMBOL(<item>) WHERE %control-ZZClassZ## = if_abap_behv=>mk-on. UPDATE z##_tritem SET zzclassz## = @<item>-ZZClassZ## WHERE item_uuid = @<item>-ItemUuid. ENDLOOP. ENDMETHOD.
  7. Implement an identical loop over the items that were just created and require an update of the booking class field.

    Caution

    When the framework executes the additional save logic, it already executed the normal save logic. The normal save logic already created the new entries in the database table. Therefore, do not use the ABAP SQL statement INSERT or you will get duplicate key errors from the database. Instead, use the ABAP SQL statement UPDATE as before.
    1. Adjust the code as follows:

      Code Snippet
      123456789101112131415161718192021
      METHOD save_modified. LOOP AT update-item ASSIGNING FIELD-SYMBOL(<item>) WHERE %control-ZZClassZ## = if_abap_behv=>mk-on. UPDATE z##_tritem SET zzclassz## = @<item>-ZZClassZ## WHERE item_uuid = @<item>-ItemUuid. ENDLOOP. LOOP AT create-item ASSIGNING <item> WHERE %control-ZZClassZ## = if_abap_behv=>mk-on. UPDATE z##_tritem SET zzclassz## = @<item>-ZZClassZ## WHERE item_uuid = @<item>-ItemUuid. ENDLOOP. ENDMETHOD.

      Hint

      Alternatively, you can first merge the lines of update-item and create-item in one internal table before you do the loop. This is possible, because update and create are typed with the identical derived type. The code could then, for example, look as follows:
      Code Snippet
      12345678910111213
      METHOD save_modified. DATA(items) = update-item. APPEND LINES OF create-item TO items. LOOP AT items ASSIGNING FIELD-SYMBOL(<item>) WHERE %control-ZZClassZ## = if_abap_behv=>mk-on. UPDATE z##_tritem SET zzclassz## = @<item>-ZZClassZ## WHERE item_uuid = @<item>-ItemUuid. ENDLOOP. ENDMETHOD.
  8. Activate the behavior extension implementation and test the preview of the OData UI service.

    1. Press Ctrl + F3 to activate the development object.

    2. Reopen the preview of the OData UI service and choose Go to display the list of flight travels.

    3. Open the object page for a flight travel that lies in the future and choose Edit.

    4. Choose Create to create a new flight travel item.

    5. Enter valid values for all flight travel item fields and save the data.

      Result

      The value that you entered in the Booking Class field is stored in the Z##_TRITEM database table.

Task 3: Extend with Validation

Make sure the user can only enter allowed values in the extension field ZZClassZ##. To do so, extend the behavior for the flight travel items with a validation (suggested name: ZZvalidateClass) and implement it using the CDS view entity /LRN/437_I_ClassStdVH as the data source.

Steps

  1. Edit the behavior extension on data model level Z##X_R_TRAVEL_CLASS. For the flight travel item entity, define a new validation (suggested name: ZZvalidateClass) that is triggered during the create operation or by changes to the booking class field ZZClassZ##.

    1. Adjust the code as follows:

      Code Snippet
      12345678
      extend behavior for Item with additional save { validation ZZvalidateClass on save { create; field ZZClassZ##; } }
  2. Perform a syntax check.

    1. Press Ctrl + F2 to perform a syntax check.

    2. Analyze the Problems view below the editor.

  3. Extend the draft determine action Prepare and add the validation.

    Hint

    The draft determine action Prepare is part of the behavior of the root entity. To address the validation of a child entity, you have to use the alias name of the child entity as a prefix.
    1. Adjust the code as follows:

      Code Snippet
      1234567
      extend behavior for Travel { extend draft determine action Prepare { validation Item~ZZvalidateClass; } }
  4. Activate the behavior extension and use a quick fix to add the validation method to the local handler class.

    1. Press Ctrl + F3 to activate the development object.

    2. Place the cursor on the name of the validation ZZvalidateClass and press Ctrl + 1 to invoke the quick assist proposals.

    3. From the list of available quick fixes, choose Add method for validation zzvalidateclass of entity z##_r_travelitem in new local class.

  5. Implement the validation in the newly created local class LHC_ITEM inside the global ABAP class ZBP_##X_R_TRAVEL_CLASS. As a starting point, copy the implementation of method /lrn/validateclass from the local class LHC_ITEM in the global ABAP class /LRN/BP_ZZX_R_TRAVEL_CLASS.

    Note

    We copy the model solution to save some time. The copied code is similar to the implementation of the flight date validation. The main difference is the existence check, if the booking class is not initial. But that is something you already implemented in the customer ID validation.
    1. Choose Ctrl + Shift + A, enter /LRN/BP_ZZX_R_TRAVEL_CLASS , and choose OK.

    2. Navigate to the Local Types tab and scroll down to the METHOD /lrn/validateclass. statement.

    3. Select the entire code betweenMETHOD /lrn/validateclass. and the following ENDMETHOD. statement and press Ctrl + C.

    4. Return to your own class ZBP_##X_R_TRAVEL_CLASS. In the local class LHC_ITEM contained therein, place the cursor between METHOD ZZvalidateClass. and the following ENDMETHOD. and choose Ctrl + V.

  6. In the copied code, find the READ ENTITIES OF statement and replace /lrn/437h_r_travel with the business object Z##_R_TRAVEL that you extend in this exercise.

    1. Adjust the code as follows:

      Code Snippet
      12345
      READ ENTITIES OF Z##_R_Travel IN LOCAL MODE ENTITY Item FIELDS ( AgencyId TravelId /lrn/classzit ) WITH CORRESPONDING #( keys ) RESULT DATA(items).
  7. Everywhere in the implementation, replace the extension field name that is used in the model solution (/lrn/classzit) with your own extension field name (ZZClassZ##).

    Hint

    Use the Find/Replace function of the editor.
    1. Press Ctrl + F to invoke the search function.

    2. Make sure that the Find field contains /lrn/classzit.

    3. In the Replace field, enter ZZClassZ##, and choose Replace all.

  8. Activate the behavior extension implementation and test the validation in the preview of the OData UI service.

    1. Press Ctrl + F3 to activate the development object.

    2. Reopen the preview of the OData UI service and choose Go to display the list of flight travels.

    3. Open the object page for a flight travel that lies in the future and choose Edit.

    4. Choose Create to create a new flight travel item.

    5. Enter an invalid value in the Booking Class field, for example X, and save the data.

      Result

      You see the error message Booking Class X does not exist.

Task 4: Optional: Extend with Side Effect

Extend the behavior definition on data model level Z##_R_TRAVEL with a determine action (suggested name: ZZcheckClass) and let it trigger the extension validation ZZvalidateClass. Then extend the behavior definition with a side effect that executes the determine action after the user entered a value in the Booking Class field.

To get the scenario running, the created determine action must finally be exposed to the UI service via an extension of the projection behavior definition.

Note

Ideally, we would extend the behavior projection with the side effect because it is only relevant for the UI service. However, the extension of behavior projections with side effects is currently not yet supported. Therefore, we add the side effect to the behavior definition on data model level.

Steps

  1. Edit the behavior extension on data model level Z##X_R_TRAVEL_CLASS. For the travel item entity, define a new determine action (suggested name: ZZcheckClass).

    1. Adjust the code as follows:

      Code Snippet
      12345678910111213
      extend behavior for Item with additional save { validation ZZvalidateClass on save { create; field ZZClassZ##; } determine action ZZcheckClass { } }
  2. Specify that no authorizations are required to execute the determine action.

    1. Adjust the code as follows:

      Code Snippet
      12345678910111213
      extend behavior for Item with additional save { validation ZZvalidateClass on save { create; field ZZClassZ##; } determine action ( authorization : none ) ZZcheckClass { } }
  3. Assign the validation of the booking class field ZZvalidateClass to the determine action.

    1. Adjust the code as follows:

      Code Snippet
      12345678910111213
      extend behavior for Item with additional save { validation ZZvalidateClass on save { create; field ZZClassZ##; } determine action ( authorization : none ) ZZcheckClass { validation ZZvalidateClass; } }
  4. Extend the behavior definition with a side effect that executes the determine action ZZcheckClass after the user made an entry in the booking class field.

    1. Adjust the code as follows:

      Code Snippet
      123456789101112
      determine action ( authorization : none ) ZZcheckClass { validation ZZvalidateClass; } side effects { determine action ZZcheckClass executed on field ZZClassZ## affects messages; } }
  5. Activate the extension of the behavior definition.

    1. Press Ctrl + F3 to activate the development object.

  6. The last step is to make the created determine action ZZcheckClass available for the UI service via an extension of the projection behavior definition. To do this, as a first step declare your projection behavior definition Z##_C_TRAVEL and the Z##_C_TravelItem entity contained therein as extensible. Don't forget to activate your changes.

    1. Edit your projection behavior definition Z##_C_TRAVEL.

    2. Adjust your code as follows:

      Code Snippet
      1234567891011121314
      projection; strict ( 2 ); use draft; use side effects; extensible; [...] define behavior for Z## _C_TravelItem use etag extensible {
    3. Press Ctrl + F3 to activate the development object.

  7. Now create an extension for the projection behavior definition (suggested name Z##X_C_TRAVEL_CLASS). In the implementation of the extension, make the determine action ZZcheckClass available for the Fiori application.

    1. In the Project Explorer, open the context menu for your projection behavior definition Z##_C_TRAVEL.

    2. Choose New Behavior Extension.

    3. In the Name field, enter Z##X_C_TRAVEL_CLASS and in the Description field, enter Extend Travel Item with Booking Class.

    4. Choose Next.

    5. Select a transport request and choose Finish.

    6. Adjust the implementation of the extension as follows:

      Code Snippet
      123456
      extension for projection; extend behavior for Z##_C_TravelItem { use action ZZcheckClass; }
  8. Activate the behavior extension on projection level and test the result in a preview of your OData UI service.

    1. Press Ctrl + F3 to activate the development object.

    2. Reopen the preview of the OData UI service and choose Go to display the list of flight travels.

    3. Open the object page for a flight travel that lies in the future and choose Edit.

    4. Choose Create to create a new flight travel item.

    5. Enter an invalid value in the Booking Class field, for example X. Press Tab to leave the input field.

      Result

      This triggers the determine action and you see the error message Booking Class X does not exist.