Lets checkout the ABAP object oriented approach for reports when you want to get data from different data sources – Database and/or Archive .
Introduction
Almost all clients use archiving to control the primary DB size and to make sure it doesn’t grow too big. If primary DB would be big, it would have its own performance impact. But this not the topic for this article. In this article, I want to give you a pattern which you can follow in your developments where you have more than one data source – Database and Archive.
In this example, we would take PBS as the archive add-on as example. But, in reality you can implement this approach in any multiple data selection.
Report Requirement
This report is very basic report to display data from DB as well as archive. The selection screen has other reporting criteria along with these options:
As name suggest, the data can be selected from DB, archive or both
Procedural Design
In simple procedural design, this report selection would be using the IF conditions to restrict the selection based on the selected option. It is not necessarily an issue, but this design can be modified to be more modular, following more design principles, etc.
I’m providing only the part where there is a data selection and also there is different logic.
* Block 1 of selection screen SELECTION-SCREEN BEGIN OF BLOCK block1 WITH FRAME TITLE text-001. SELECT-OPTIONS : s_vendor FOR v_vendor. SELECTION-SCREEN END OF BLOCK block1. * Display Data Retrieval Options SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-049. PARAMETERS: p_rb_all TYPE c RADIOBUTTON GROUP rd2, p_rb_arc TYPE c RADIOBUTTON GROUP rd2 , p_rb_db TYPE c RADIOBUTTON GROUP rd2 DEFAULT 'X'. SELECTION-SCREEN END OF BLOCK b2. START-OF-SELECTION. IF p_rb_db = 'X' OR p_rb_all = 'X'. SELECT ebeln bukrs bsart lifnr waers submi INTO TABLE i_ekko FROM ekko WHERE lifnr IN s_vendor[]. ENDIF. IF p_rb_ar = 'X' OR p_rb_all = 'X'. DATA: tab93 TYPE STANDARD TABLE OF ekko. DATA: ls_tab93 LIKE LINE OF tab93. DATA: ls_ekko LIKE LINE OF i_ekko. CALL FUNCTION '/PBS/SELECT_INTO_TABLE' EXPORTING archiv = 'CMM' option = " tabname = 'EKKO' clr_itab = 'X' schl1_name = 'LIFNR' TABLES i_tabelle = tab93 schl1_in = s_vendor[] EXCEPTIONS eof = 4 OTHERS = 2. LOOP AT tab93 INTO ls_tab93. MOVE ls_tab93-ebeln TO ls_ekko-ebeln . MOVE ls_tab93-bukrs TO ls_ekko-bukrs . MOVE ls_tab93-bsart TO ls_ekko-bsart . MOVE ls_tab93-lifnr TO ls_ekko-lifnr . MOVE ls_tab93-waers TO ls_ekko-waers . MOVE ls_tab93-submi TO ls_ekko-submi . APPEND ls_ekko TO i_ekko . ENDLOOP. DESCRIBE TABLE i_ekko LINES sy-tfill. IF sy-tfill GT 0. sy-subrc = 0. ENDIF. ENDIF. IF p_rb_db = 'X' OR p_rb_all = 'X'. SELECT ekpo~ebeln ekpo~ebelp ekpo~matnr ekpo~bukrs ekpo~werks ekpo~menge ekpo~netwr ekkn~ps_psp_pnr eket~eindt ekpo~mwskz ekpo~loekz INTO TABLE i_ekpo FROM ekpo JOIN ekkn ON ( ekpo~ebeln = ekkn~ebeln AND ekpo~ebelp = ekkn~ebelp ) JOIN eket ON ( ekpo~ebeln = eket~ebeln AND ekpo~ebelp = eket~ebelp ) FOR ALL ENTRIES IN i_ekko WHERE ekpo~ebeln EQ i_ekko-ebeln. ENDIF. IF p_rb_ar = 'X' OR p_rb_all = 'X'. "use same PBS FM to get the data from EKPO, EKKN, EKET ENDIF. "Vendor name selection "fill up final table "display data in ALV
Object Oriented Approach
To avoid the IF conditions and to have separate classes for the different data sources, I use these design. This design is very much dependent on the Decorator Design Pattern. If you are not yet familiar with decorator, I suggest you make yourself familiar with decorator before continue reading here.
The design is based on following idea:
- Create the class for the primary data selection.
- Using this class, inherit classes for each data source.
- At time of instantiating the object, establish the decorator relationship
- Within the methods which are redefined, call the decorator methods.
- Get back the data from decorator objects into the primary data object.
Here you are not fully using the decorator design pattern. But, you can if you have more than couple different data-sources.
Another problem I’m facing is to make sure same data selection doesn’t get reselected over and over
Redesigned Code Lines
Again, this is smaller version of the original program with only relevant parts. You can create the full blown solution using ABAP Object Oriented Approach for Reports – Redesign
* CLASS zcl_cda_db DEFINITION. PUBLIC SECTION. METHODS: constructor IMPORTING io_next TYPE REF TO zcl_cda_db OPTIONAL. METHODS: get_data. PROTECTED SECTION. TYPES: tt_ekko TYPE STANDARD TABLE OF ty_ekko, tt_ekpo TYPE STANDARD TABLE OF ty_ekpo. METHODS: select_ekko, select_ekpo_ekkn, merge_data, select_vendor_names, fill_final_table. DATA: i_ekko TYPE tt_ekko, i_ekpo TYPE tt_ekpo. DATA: o_decorator TYPE REF TO zcl_cda_db. ENDCLASS. "zcl_cda_db DEFINITION * CLASS zcl_cda_arch DEFINITION INHERITING FROM zcl_cda_db. PUBLIC SECTION. METHODS: constructor IMPORTING io_next TYPE REF TO zcl_cda_db OPTIONAL. PROTECTED SECTION. METHODS: select_ekko REDEFINITION, select_ekpo_ekkn REDEFINITION. ENDCLASS. "zcl_cda_arch DEFINITION **__SELECTION-SCREEN_____________________________________________________* DATA: v_vendor TYPE ekko-lifnr. * Block 1 of selection screen SELECTION-SCREEN BEGIN OF BLOCK block1 WITH FRAME TITLE text-001. SELECT-OPTIONS : s_vendor FOR v_vendor. SELECTION-SCREEN END OF BLOCK block1. * Display Data Retrieval Options SELECTION-SCREEN BEGIN OF BLOCK b2 WITH FRAME TITLE text-049. PARAMETERS: p_rb_all TYPE c RADIOBUTTON GROUP rd2, p_rb_arc TYPE c RADIOBUTTON GROUP rd2 , p_rb_db TYPE c RADIOBUTTON GROUP rd2 DEFAULT 'X'. SELECTION-SCREEN END OF BLOCK b2. **__START-OF-SELECTION_________________________________________________* START-OF-SELECTION. DATA: o_data TYPE REF TO zcl_cda_db. DATA: lo_data_a TYPE REF TO zcl_cda_arch. IF p_rb_db = 'X'. CREATE OBJECT o_data. ENDIF. IF p_rb_arc = 'X'. CREATE OBJECT o_data TYPE zcl_cda_arch. ENDIF. IF p_rb_all = 'X'. CREATE OBJECT lo_data_a. CREATE OBJECT o_data EXPORTING io_next = lo_data_a. ENDIF. o_data->get_data( ). * CLASS zcl_cda_db IMPLEMENTATION. * METHOD constructor. o_decorator = io_next. ENDMETHOD. "constructor * METHOD get_data. " data from data source me->select_ekko( ). me->select_ekpo_ekkn( ). " merge data from decorator objects into here me->merge_data( ). "Always from primary data source me->select_vendor_names( ). "fill up the final table me->fill_final_table( ). ENDMETHOD. "get_Data * METHOD select_ekko. SELECT ebeln bukrs bsart lifnr waers submi INTO TABLE me->i_ekko FROM ekko WHERE lifnr IN s_vendor[]. CHECK o_decorator IS BOUND. o_decorator->select_ekko( ). ENDMETHOD. "select_ekko * METHOD select_ekpo_ekkn. SELECT ekpo~ebeln ekpo~ebelp ekpo~matnr ekpo~bukrs ekpo~werks ekpo~menge ekpo~netwr ekkn~ps_psp_pnr eket~eindt ekpo~mwskz ekpo~loekz INTO TABLE me->i_ekpo FROM ekpo JOIN ekkn ON ( ekpo~ebeln = ekkn~ebeln AND ekpo~ebelp = ekkn~ebelp ) JOIN eket ON ( ekpo~ebeln = eket~ebeln AND ekpo~ebelp = eket~ebelp ) FOR ALL ENTRIES IN i_ekko WHERE ekpo~ebeln EQ i_ekko-ebeln. CHECK o_decorator IS BOUND. o_decorator->select_ekpo_ekkn( ). ENDMETHOD. "select_ekpo_ekkn * METHOD merge_data. CHECK o_decorator IS BOUND. APPEND LINES OF: o_decorator->i_ekko TO me->i_ekko, o_decorator->i_ekpo TO me->i_ekpo. ENDMETHOD. "merge_data * method select_vendor_names. "get NAME1 from LFA1 for all entries in I_EKKO ENDMETHOD. * method fill_final_Table. "move data from all tables into final table for display ENDMETHOD. ENDCLASS. "zcl_cda_db IMPLEMENTATION * CLASS zcl_cda_arch IMPLEMENTATION. * METHOD constructor. super->constructor( io_next ). ENDMETHOD. "constructor * METHOD select_ekko. DATA: tab93 TYPE STANDARD TABLE OF ekko. DATA: ls_tab93 LIKE LINE OF tab93. DATA: ls_ekko LIKE LINE OF me->i_ekko. CALL FUNCTION '/PBS/SELECT_INTO_TABLE' EXPORTING archiv = 'CMM' option = " tabname = 'EKKO' clr_itab = 'X' schl1_name = 'LIFNR' TABLES i_tabelle = tab93 schl1_in = s_vendor[] EXCEPTIONS eof = 4 OTHERS = 2. LOOP AT tab93 INTO ls_tab93. MOVE ls_tab93-ebeln TO ls_ekko-ebeln . MOVE ls_tab93-bukrs TO ls_ekko-bukrs . MOVE ls_tab93-bsart TO ls_ekko-bsart . MOVE ls_tab93-lifnr TO ls_ekko-lifnr . MOVE ls_tab93-waers TO ls_ekko-waers . MOVE ls_tab93-submi TO ls_ekko-submi . APPEND ls_ekko TO me->i_ekko . ENDLOOP. DESCRIBE TABLE me->i_ekko LINES sy-tfill. IF sy-tfill GT 0. sy-subrc = 0. ENDIF. ENDMETHOD. "select_ekko METHOD select_ekpo_ekkn. "similarly select the data from PBS "for the tables EKPO, EKET, EKKN ENDMETHOD. "select_ekpo_ekkn ENDCLASS. "zcl_cda_arch IMPLEMENTATION
When RB_ALL is selected and primary DB object is being instantiated
When method SELECT_EKKO is being called
Do let me know your thoughts in the comments.
Further Reading
Explore all other Design patterns..
- ABAP Object Design Patterns – Singleton
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 1
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 2
- ABAP Objects Design Patterns – Model View Controller (MVC) Part 3
- ABAP Objects Design Patterns – Decorator
- ABAP Objects Design Patterns – Factory Method
- ABAP Objects Design Patterns – Observer
- Case Study: Observer Design Pattern Usage
- ABAP Objects Design Patterns – Abstract Factory
- OO Design Pattern Decorator – Why do we need to use helper variable?
- ABAP Objects Design Patterns – Facade
- ABAP Objects Design Patterns – Adapter
- ABAP Objects Design Patterns – Composite
- ABAP Objects Design Patterns – Iterator
- Iterator Design Pattern to access Linked List in ABAP Objects
- ABAP Objects Design Patterns – Proxy
- ABAP Objects Design Patterns – Prototype
- ABAP Objects Design Patterns – Singleton Factory
- ABAP Object Oriented Approach for Reports – Initial Design
- ABAP Object Oriented Approach for Reports – Redesign
- ABAP Objects Design Patterns – Builder
- ABAP Objects Design Patterns Singleton Usage
- ABAP MVC – Model View Controller Discussion
- Object Oriented Approach for Reports with multiple Datasource
- OO ABAP – Selection Object with Direct Access
- OO ABAP – Selection Criteria Object using RS_REFRESH_FROM_SELECT OPTIONS
- ABAP Factory Method Using SWITCH
Awesome presentation as always. Thanks for sharing.
Regards
Mohinder
Awesome presentation as always. Thanks for sharing.
Regards
Mohinder
Hi Naimesh.
Thx for the info.
I would like to know how do you use the Function “‘/PBS/SELECT_INTO_TABLE”. Maybe do you install an extra software to available that function?
I’ll appreciate your comments about it.
Hello Jose,
PBS is archiving add-on for SAP. You can find more on it at – PBS Add on SAP
Thanks.
Hi Naimesh,
excellent as almost always.
Your motivation and energy appreciated.
Now my 2 cents: Not 100 % in line with oo design and reuse idea is the direct use of selection screen values as parameters and select-option ranges inside local class methods.
OK, I know the effort to create setter and getter methods just for them is not justified at all.
Just to ensure modularity and have qick generation times I create my classes as global dictionary classes.
For access to selection-screen values I use the dynamic assign. SAP warns since almost 20 years (probably since R/3 and ABAP) not to use it as it may be changed incompatible at any time.
I expect no change before the end of the world, later I don’t care.
Now see my methods to access parameters and select-option range tables:
selection screen access Class definition
selection screen access Class implementation
The GET methods are used whenever values from selection screen are used. The SET methods are useful for INITIALIZATION methods called in INITIALIZATION event of report.
Here some code samples of how the methods may be used.
implementation samples
The calling report has just the parameters and select-options and the events initialization and start-of-selection.
In initialization I have a CREATE OBJECT and a ->initialization( ).
start-of-selection has the method call ->start_of_selection( ).
I’d like to hear what you think about this approach.
Thank you and best regards, Clemens
Hi folks,
sorry the code formatter crunched my field-symbols. They are obvously confued with html tags. So the code is not syntactically correct and hard to understand. When I know the solution, I will post the code in human and machine-readable form.
Regards, Clemens
Hi Clemens,
Hope your are doing great 🙂
I feel that Naimesh purposefully didn’t handle the selection option here because the sole intention was to explain about fetching data from multiple data sources using OO pattern, There are few posts already in his blogs which explains the way of handling the selection screen variables in OO.
By the way, I use a different method of handling the selection screen values, in a separate screen handler class I use the function RS_REFRESH_FROM_SELECTOPTIONS and build the values internally, then at later point access those values using public methods. For simplicity, I always pass the screen values via constructor and store it in attributes of class.
BR
Kesav
Hello Kesav,
I’ll take the liberty to reply to your comment.
Yes, you are right that I deliberately used the select options in the classes as my main idea was to show the different data source selection. As you have pointed out the selection screen related class based design can be found in ABAP Object Oriented Approach for Reports – Redesign.
I would love to see your design using the FM and see how it in action.
Thanks,
Naimesh Patel
Here is my implementation using the Function Module Kesav mentioned. I do not use get and set-methods because the select-options are set class-internally and can be gotten as read only attributes.
Hello Jani80K,
Apologies for Field Symbol is being disappeared from this comment and thanks for providing your code lines.
The implementation looks promising. I would try to publish as separate code lines so the FS are not removed.
Thanks,
Naimesh Patel
[…] to Clemens Li for sharing this utility class in his comment on the article Object Oriented Approach for Reports with multiple […]
[…] object. Keshav and Jani80k has suggested that we also can use the FM RS_REFRESH_FROM_SELECTOPTIONS. Jani80K provided the implementation as well in the article Object Oriented Approach for Reports with […]