Cerca nel blog

giovedì 19 dicembre 2024

Funzionalità MESH

Funzionalità MESH


Spesso ci capita di lavorare con complesse relazioni tra tabelle, ad esempio: BKPF->BSEG->LFA1->LFBK. Spesso, ci affidiamo a cicli nidificati e condizioni di chiave ripetitive durante la lettura della tabella di intestazione/elemento per gestire tali relazioni. Ma c'è un modo migliore chiamato Mesh.

La mesh è fondamentalmente una struttura complessa che consente di recuperare record dipendenti da più tabelle.

Una Mesh separa la definizione di una relazione dal suo utilizzo: se ad esempio un record di elemento ha un campo "parent_key" che contiene la chiave del suo record di intestazione, questo viene definito solo una volta all'interno della Mesh. Senza una Mesh, questa informazione viene ripetuta in ogni LOOP in cui iteriamo sugli elementi di un'intestazione e in ogni READ TABLE in cui leggiamo l'intestazione di un elemento. Se c'è una modifica nel modello di dati, nel migliore dei casi solo la definizione di Mesh deve essere modificata ma non tutti i LOOP e le READ TABLE.

Come componenti di questo tipo di struttura sono consentite solo tabelle interne e riferimenti a tabelle interne. Nel contesto Mesh, queste tabelle interne sono chiamate "nodi", ma sono comunque solo tabelle interne e, oltre alle speciali operazioni Mesh che vedremo nelle prossime sezioni, possiamo fare qualsiasi cosa con loro come possiamo fare con una tabella interna dichiarata all'esterno di una Mesh.

Associazioni inverse

Per ogni associazione definita nella Mesh, il runtime genera automaticamente l'associazione inversa, ovvero scambia il nodo sorgente e quello di destinazione e di conseguenza l'ordine dei campi nella condizione di relazione. Tale associazione "specchiata" ha lo stesso nome dell'originale, ma "^" come prefisso e "~" seguito dal nuovo nodo di destinazione (il nodo sorgente originale) come suffisso.

Esempio

REPORT zprova_mesh.

TYPES: tt_bkpf_2 TYPE HASHED TABLE OF bkpf WITH UNIQUE KEY  bukrs belnr gjahr,
       tt_bseg_2 TYPE HASHED TABLE OF bseg WITH UNIQUE KEY  bukrs belnr 
                                                            gjahr buzei,
       tt_lfa1_2 TYPE HASHED TABLE OF lfa1 WITH UNIQUE KEY  lifnr,

       BEGIN OF MESH ty_mesh,
         bkpf TYPE tt_bkpf_2 ASSOCIATION _bseg TO bseg ON bukrs = bukrs
                                                    AND belnr = belnr
                                                    AND gjahr = gjahr,
         bseg TYPE tt_bseg_2 ASSOCIATION _bkpf TO bkpf ON bukrs = bukrs
                                                    AND belnr = belnr
                                                    AND gjahr = gjahr
                           ASSOCIATION _lfa1 TO lfa1 ON lifnr = lifnr,
         lfa1 TYPE tt_lfa1_2 ASSOCIATION _bseg TO bseg ON lifnr = lifnr,
       END OF MESH ty_mesh.


PARAMETERS: p_vendor TYPE lifnr OBLIGATORY.

START-OF-SELECTION.
  SELECT *
    FROM lfa1
    INTO TABLE @DATA(gt_lfa1)
    WHERE lifnr = @p_vendor.

  SELECT *
    INTO TABLE @DATA(gt_bseg)
    FROM bseg
    FOR ALL ENTRIES IN @gt_lfa1
    WHERE lifnr = @gt_lfa1-lifnr.

  SELECT *
    INTO TABLE @DATA(gt_bkpf)
    FROM bkpf
    FOR ALL ENTRIES IN @gt_bseg
    WHERE bukrs = @gt_bseg-bukrs
      AND belnr = @gt_bseg-belnr
      AND gjahr = @gt_bseg-gjahr.


  DATA(lt_mesh) = VALUE ty_mesh(
          bkpf = VALUE #( FOR ls_bkpf IN gt_bkpf
                        ( bukrs     = ls_bkpf-bukrs
                          belnr     = ls_bkpf-belnr
                          gjahr     = ls_bkpf-gjahr
                        )
                       )

          bseg = VALUE #( FOR ls_bseg IN gt_bseg
                        ( bukrs     = ls_bseg-bukrs
                          belnr     = ls_bseg-belnr
                          gjahr     = ls_bseg-gjahr
                          buzei     = ls_bseg-buzei
                          lifnr     = ls_bseg-lifnr
                        )
                       )

          lfa1 = VALUE #( FOR ls_lfa1 IN gt_lfa1
                        ( lifnr     = ls_lfa1-lifnr
                          name1     = ls_lfa1-name1
                          name2     = ls_lfa1-name2
                          name3     = ls_lfa1-name3
                          name4     = ls_lfa1-name4
                        )
                       )
  ).


* Stampiamo i dati della BSEG
  WRITE: / ' Dati della BSEG '.
  WRITE: / ' --------------- '.
  LOOP AT lt_mesh-lfa1\_bseg[ lt_mesh-lfa1[ lifnr = p_vendor ] ] 
        ASSIGNING FIELD-SYMBOL(<lfs_bseg>).
    WRITE: / <lfs_bseg>-bukrs, <lfs_bseg>-belnr, 
             <lfs_bseg>-gjahr, <lfs_bseg>-buzei, <lfs_bseg>-lifnr.
  ENDLOOP.

* Stampiamo i dati della BKPF
  WRITE: / ' Dati della BKPF '.
  WRITE: / ' --------------- '.
  LOOP AT lt_mesh-lfa1\_bseg[ lt_mesh-lfa1[ 
lifnr = p_vendor ] ]\_bkpf[ ] 
        ASSIGNING FIELD-SYMBOL(<lfs_bkpf>).
    WRITE: / <lfs_bkpf>-bukrs, <lfs_bkpf>-belnr, <lfs_bkpf>-gjahr.
  ENDLOOP.

* Stampiamo i dati della BSEG
  WRITE: / ' Dati della BSEG con Associazione '.
  WRITE: / ' --------------- '.
  LOOP AT lt_mesh-lfa1\^_lfa1~bseg[ lt_mesh-lfa1[ lifnr = p_vendor ] ] 
          ASSIGNING FIELD-SYMBOL(<lfs_bseg2>).
    WRITE: / <lfs_bseg2>-bukrs, <lfs_bseg2>-belnr, 
             <lfs_bseg2>-gjahr, <lfs_bseg2>-buzei, <lfs_bseg2>-lifnr.
  ENDLOOP.

* Stampiamo i dati della BKPF
  WRITE: / ' Dati della BKPF con Associazione '.
  WRITE: / ' --------------- '.
LOOP AT lt_mesh-lfa1\^_lfa1~bseg[ lt_mesh-lfa1[ lifnr = p_vendor ] ]\^_bseg~bkpf[ ]
        ASSIGNING FIELD-SYMBOL(<lfs_BKPF2>).
    WRITE: / <lfs_BKPF2>-bukrs, <lfs_BKPF2>-belnr, <lfs_BKPF2>-gjahr.
  ENDLOOP.

END-OF-SELECTION.



Eseguendo il report: