BRF+ does not support enforcing unique key constraints on its tables, even if the table is bound to a DDIC table type with a unique key. There is also no out of the box functionality to remove duplicates from a BRF+ table. I needed a simple and performance efficient solution for this requirement.

tl;dr

  • The duplicate removal can be implemented by a simple ABAP function using SORT and DELETE ADJACENT DUPLICATES
  • Using generic types for the method parameters makes for efficient procedure calls from BRF+

Business requirement

Our rule set consists of a list of rules that depending on input data modify parts (called entities) of a large data model (SAP Material). Due to performance constraints in the underlying system, only changed parts shall be written back and written only once. There is a n:m relationship between rules and data model parts. If a rule changes one or more entities, it adds the entity names to a list of entities to be written.

Implementation

ABAP has built-in commands for removing duplicate entries from an internal table via the commands SORT and DELETE ADJACENT DUPLICATES. We implement a static helper method that does the sort & delete.

Alas, calling from BRF+ into ABAP comes at some price, as the framework uses a different data representation internally (inside BRF+) then externally (in the ABAP world), e.g. all text data is converted into a STRING type, and quantities and amounts are represented by structures (for details, see IF_FDT_TYPES in your system). So for every procedure call, the system needs to do a conversion internal → external for converting the method parameters when invoking the method and external → internal when retrieving the result.

Luckily we can circumvent the conversion process by working with the internal representation directly. This is done by using generic types for our method parameter.

Table type

table_type.PNG

The BRF+ table consists only of a text line. The corresponding ABAP type is

STANDARD TABLE OF if_fdt_types=>element_text WITH DEFAULT KEY

which is an unstructured table of STRING elements.

Method signature


CLASS-METHODS make_unique_text_table
       CHANGING
         !ct_text TYPE TABLE.

The CHANGING parameter ct_text can be passed any table, triggering BRF+ to pass in its internal table format. Note that this also eliminates checks on the caller side, so you need to be careful in BRF+ later on to pass in only table types the method can actually work with.

Method implementation


METHOD make_unique_text_table.
     "Empty list means nothing to do
     IF lines( ct_text ) < 2.
       RETURN.
     ENDIF.
     "Sort & make unique
     SORT ct_text BY table_line.
     DELETE ADJACENT DUPLICATES FROM ct_text.
   ENDMETHOD.

The implementation merely contains the SORT & DELETE operations.

Procedure call

/wp-content/uploads/2014/12/procedure_call_616654.png

Using an expression of type Procedure Call makes the function available to BRF+.

Generated call

/wp-content/uploads/2014/12/generated_call_616734.png

The invocation code generated by BRF+ does not contain any copying of the table or parameter conversion. If you modify the parameter type to a concrete DDIC type, you will see that the method invocation is wrapped in conversion code that copies the internal BRF+ table to the table type you specified.

To Infinity! And beyond.

The above mentioned technique for efficient procedure calls could be extended to structured tables as well if you re-create the BRF+ tables internally used structure in your ABAP code. You can have a look a the generated BRF+ code to understand how BRF+ generates its internal types. You would then just have to cast the generic type to the concrete one and do your ABAP processing on the data.

Note however that you should only using ABAP coding as a last resort and for simplistic self-contained functionality, and stay in BRF+ as long as possible, for countless reasons (performance being the least of them). I have been using BRF+ for some years now, and this is the first occurrence of missing functionality that I encountered, and it was a minor one.

To report this post you need to login first.

4 Comments

You must be Logged on to comment or reply to a post.

  1. Christian Lechner

    Hi Jürgen,

    I like your post as you address several things that are from my point of view important when dealing with BRFplus. From my experience it is inevitable to sometimes transfer infrastructural tasks (like in your case DELETE ADJACENT DUPLICATES) to custom code using the procedure expression. From my experience you run into several problems when extensively modeling ABAP coding or ABAP expression in BRFplus. Although you have most of the basic statements at hand to do so you will run into several problems like a huge context (due to intermediate results etc.) that will kill the performance (and lead to dumps the design time). The question is when to do so (and I do not really have a generic answer on that). 

    When you have a lot of “infrastructural” work to do that has no influence on the business rules from a business perspective and does not harm the agility of the solution you can and sometimes should use the “enhancement option” of an ABAP call via the procedure call expression.  As a severe constraint and as you stress it you certainly have to know what you do (or what BRFplus does) when you jump towards custom code. Especially the performance i. e. the mapping of data elements is an important aspect where you are perfectly right.

    Hope to read more about you experiences with BRFplus

    Cheers

    Christian

    (0) 
  2. khushbu Agarwal

    Hi Jürgen,


    I have seen that whenever we are having call from BRF+ to ABAP and than back to BRF+ , the process become a bit time consuming.


    I have also faced the need of doing the delete adjacent duplicates and have done that in BRFplus only with the help of nested LOOP operations and TABLE Operation expression.


    Just want to know which is better approach in terms of performance.


    Regards,

    Khushbu

    (0) 
    1. Jürgen Lukasczyk Post author

      I have seen that whenever we are having call from BRF+ to ABAP and than back to BRF+ , the process become a bit time consuming.

      From my experience, the performance hit is caused solely by the conversion of BRF+ types to ABAP on calling and then the other way round for return values, with Quantities and Timepoints being most performance intensive, as those types are structures in BRF+.


      The above code avoids this conversion, so the penalty is nearly in the range of a plain function call.

      I have also faced the need of doing the delete adjacent duplicates and have done that in BRFplus only with the help of nested LOOP operations and TABLE Operation expression.

      Just want to know which is better approach in terms of performance.

      I’d predict that my approach is faster, because you cannot beat ABAP built-in functions w/ your own code, and nested BRF+ Loops and TableOps get turned in ABAP code lines.

      But you can never be sure w/o measuring, and since I do not have your implementation (which I think is blog worthy by itself) and mine could be easily copied to your system, I suggest you do the measuring.

      Looking forward to hear about your results. 🙂

      (0) 
  3. Arijit Das

    Hi Jürgen

    I achieved this with the Table Operation Has Exactly / Has At Least. Both works fine. Without this I was getting duplicates of data stored in the database table which was retrieved by a Function (and subsequent Ruleset, TabOps, Loop, DB Lookup). Also I was getting blank data even though the selection criteria was valid.

    Regards Arijit

    (0) 

Leave a Reply