четверг, 9 января 2014 г.

Передача динамической таблицы через память.

Сразу скажу, что если у вас возникла такая задача, как написано в заголовке, то скорее всего у вас что-о не то с архитектурой. Но иногда это бывает полезным.

Итак задача. У нас есть 2 отчета. Первый может запускаться самостоятельно. Он выбирает данные по параметрам селекционного экрана и выводит их, например, в ALV-GRID. Во втором отчете, логика выборки практически такая же, но возможно отличия в выводе. Или он вообще ничего не выводит, а, например, посылает данные в другую систему через IDOC. "Копипастить" логику во втором отчете - плохо. Самое правильное - это вынести логику в отдельный ФМ/Класс. Но допустим первый отчет уже написан, переписывать его не хочется, а хочется "дернуть" его из второго и получить от него данные с минимальными изменениями.

На первый взгляд все просто. Добавляем в отчете №1 поле на "селекционник" типа такого:

parameter p_export type flag no-display default space.

А после того как выбрали данные, проверяем этот параметр. И если он установлен, то вместо того чтобы выводить данные, экспортируем их в память. Примерно так:

if p_export is initial
  perform show_data. 
else
  export data from gt_alv to memory id 'ZDYNTEST'
endif.

Второй отчет выглядит примерно так:

submit zreport1 and return
  with ...
  with ...
  with p_export eq 'X'
.
import data to gt_data from memory id 'ZDYNTEST'.

Так вроде бы все работает.
А теперь представим, что таблицу мы генерируем динамически с использованием create data, cl_abap_tabledescr и прочего. Допустим у нас есть указатель на нее в GPT_ALV (data gpt_alv type ref to data). Экспортировать сам указатель в память мы не можем, потому что даже если бы это можно было сделать, то при импорте в другой LUW (Logical Unit Work,  а submit создает именно новый LUW) это был бы указатель неизвестно на что, потому что там свое адресное пространство. А использовать память в пределах одного LUW смысла не имеет - удобнее воспользоваться статическими атрибутами класса.
Итак указатель не можем, но мы его можем привести к FIELD-SYMBOL на таблицу и ее уже передать в память. Ну примерно так:

field-symbol <t_alv> type standard table.

if p_export is initial
  perform show_data. 
else
   assign gpt_alv->* to <t_alv>.   
   export data from <t_alv> to memory id 'ZDYNTEST'
endif.

Отлично. Экспортнули. А как теперь во втором отчете эту таблицу импортировать?
Структуры мы ее не знаем - поскольку она динамическая. А в IMPORT нужно уже существующую инициализированную таблицу передавать с конкретной структурой.
Ну ОК. Можно  было бы ее построить заново, если бы можно было передать описатель типа CL_ABAP_TABLEDESCR. Но его не передать так как опять же это ссылка. Можно было бы передать описание по компонентам строки таблицы полученным через CL_ABAP_STRUCTDESCR=>GET_COMPONENTS. Но там в таблице компонентов тоже ссылки на описатели типов - и тоже их не передать. Единственным вариантом остается передача именно компонентов, но в собственных структурах с более детальным содержанием и без ссылок на описатели. Но это такой "велосипед" получается, что дешевле по затратам выйдет все-таки вынести логику из отчета №1 в отдельный ФМ или класс.

К счастью SAP уже написал такой велосипед и находится он в классе CL_SALV_BS_RUNTIME_INFO. С его использованием наш код превращается в следующее.
Отчет №1:

field-symbol <t_alv> type standard table.

if p_export is initial
  perform show_data. 
else.
  CL_SALV_BS_RUNTIME_INFO=>SET(
      display = space
      metadata = space
      data = 'X' ).

  assign gpt_alv->* to <t_alv>. 

  CL_SALV_BS_RUNTIME_INFO=>SET_DATA( DATA = <T_ALV> ).
endif.

Отчет №2:

data lpt_data type ref to data.

submit zreport1 and return
  with ...
  with ...
  with p_export eq 'X'
.

CL_SALV_BS_RUNTIME_INFO=>GET_DATA_REF(
  importing R_DATA = lpt_data ).

Вот и все - в lpt_data у нас указатель на таблицу с данными, которая была создана в отчете №1. 

Комментариев нет:

Отправить комментарий