0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【RAP】Unmanaged BOの実装 (3) Update処理

Last updated at Posted at 2022-02-22

はじめに

この記事では、RAP(ABAP RESTful Application Programming Model)で作成したUnmanaged BOにUpdate処理を追加します。

シリーズの先頭はこちら☞ 【RAP】Unmanaged BOの実装 (1)

もともとドラフトありで作成していたのですが、Editボタンを押したときにエラーになるという問題があり、ここからはドラフトなしで進めます。ドラフトなしに変える方法は以下の通りです。

・Behavior Projectionでドラフトに関連する箇所をコメントアウト

projection;
//use draft;

define behavior for ZC_PERSON_U alias Person

{
  use create;
  use update;
  use delete;

//  use action Edit;
//  use action Activate;
//  use action Discard;
//  use action Resume;
//  use action Prepare;

//  use association _FamilyMember { create; with draft; }
  use association _FamilyMember { create; }
}

define behavior for ZC_FAMILYMEMBER_U alias FamilyMember

{
  use update;
  use delete;

//  use association _Person { with draft; }
  use association _Person { }
}

OData V2のService Bindingを作成
OData V4に対応したList Reportでは、ドラフトありでないと登録、編集ボタンが表示されないため、V2版を作成します。簡単にODataバージョンを切り替えられるのがRAPの良いところです。
image.png

処理概要

現在の構成は以下のようになっています。Behavior Implementationクラスから、実際の処理を行うAdapterクラスのメソッドが呼ばれます。Adapterクラスのローカルクラスではトランザクションバッファとのやり取りを行い、SAVEのタイミングでバッファから取り出したレコードをDBに格納します。

今回、UPDATEの処理を追加するとともに、SAVEの処理を変更します。
image.png

実装ステップ

  1. Adapterクラスの実装
  2. Behavior Implementationクラスの実装

1. Adapterクラスの実装

1.1. インターフェースに型を追加

更新処理で使用する型を追加します。ts_person_controlおよびts_familymember_controlは、更新された項目を識別するためのフラグを持った型です。

zif_person_adapter
  TYPES tt_person TYPE SORTED TABLE OF zperson_u WITH UNIQUE KEY person_id.
  TYPES tt_familymember TYPE SORTED TABLE OF zfamilymember_u WITH UNIQUE KEY person_id member_id.

  TYPES BEGIN OF ts_person_control.
  TYPES  person_id TYPE ze_person_id.
  INCLUDE TYPE zsperson_x_u.
  TYPES END OF ts_person_control.

  TYPES BEGIN OF ts_familymember_control.
  TYPES person_id TYPE ze_person_id.
  TYPES member_id TYPE ze_member_id.
  INCLUDE TYPE zsfamilymember_x_u.
  TYPES END OF ts_familymember_control.

zsperson_x_u, zsfamilymember_x_uはRAP Generatorで自動生成された構造です。テーブルの項目名と同じ名称で、xsdbooleanの型を持つ項目を持っています。
image.png

1.2. ローカルクラスの実装

バッファ更新用のメソッドを追加します。また、saveメソッドに更新処理を追加します。

メソッド定義

lcl_person_buffer
CLASS lcl_person_buffer DEFINITION FINAL CREATE PRIVATE.
  PUBLIC SECTION.
    " Buffer Tables
    ...
    "更新用のバッファテーブル
    data mt_update_buffer_person type zif_person_adapter=>tt_person.
    data mt_update_buffer_familymember type zif_person_adapter=>tt_familymember.

    METHODS buffer_person_for_update IMPORTING is_person type zperson_u.
    METHODS buffer_familymember_for_update IMPORTING is_familymember type zfamilymember_u.

メソッド実装

  METHOD buffer_person_for_update.
    CHECK is_person is not initial.
    insert is_person into table mt_update_buffer_person.

  ENDMETHOD.

  METHOD buffer_familymember_for_update.
    CHECK is_familymember is not initial.
    insert is_familymember into table mt_update_buffer_familymember.
  ENDMETHOD.

  METHOD save.
    data(lt_perton) = get_person_create( ).
    data(lt_familymember) = get_familymember_create(  ).

    INSERT zperson_u FROM TABLE @lt_perton.
    UPDATE zperson_u FROM TABLE @mt_update_buffer_person. "追加

    INSERT zfamilymember_u FROM TABLE @lt_familymember.
    UPDATE zfamilymember_u FROM TABLE @mt_update_buffer_familymember.  "追加
  ENDMETHOD.

1.3. グローバルクラスの実装

Behavior Implementationクラスから呼び出されるメソッドを実装します。Behavior Implementationクラスのupdateメソッドには、更新された項目しか渡されません。更新された項目にはフラグが設定されるので、フラグをもとにどの項目が更新されたか判断し、更新されていない項目はDBから取得して埋める必要があります。また、ドラフトなしにしたことに伴って更新日、更新ユーザ等もここで設定します。

メソッド定義

zcl_person_adapter
    METHODS update_person IMPORTING is_person         TYPE zperson_u
                                    is_person_control TYPE zif_person_adapter=>ts_person_control.
    METHODS update_familymember IMPORTING is_familymember         TYPE zfamilymember_u
                                          is_familymember_control TYPE zif_person_adapter=>ts_familymember_control.

メソッド実装

  METHOD update_person.
    "TODO: clientの扱い
    "データベースから全項目を取得
    SELECT SINGLE * FROM zperson_u
    WHERE person_id = @is_person-person_id
    INTO @DATA(ls_person).

    "変更された項目で上書き
    DATA index TYPE i.
    index = 2. "キーを飛ばして2番目の項目から
    DO.
      ASSIGN COMPONENT index OF STRUCTURE is_person_control TO FIELD-SYMBOL(<is_changed>).
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.

      IF <is_changed> = abap_true.
        "clientつきの構造のため、indexを1つ進める
        ASSIGN COMPONENT index + 1 OF STRUCTURE is_person TO FIELD-SYMBOL(<field_upd>).
        ASSERT sy-subrc = 0.
        ASSIGN COMPONENT index + 1 OF STRUCTURE ls_person TO FIELD-SYMBOL(<field_current>).
        ASSERT sy-subrc = 0.
        <field_current> = <field_upd>.
      ENDIF.

      index = index + 1.
    ENDDO.

    "タイムスタンプ等の設定
    ls_person-last_changed_by = sy-uname.
    GET TIME STAMP FIELD ls_person-last_changed_at.
    GET TIME STAMP FIELD ls_person-local_last_changed_at.

    lcl_person_buffer=>get_instance( )->buffer_person_for_update( ls_person ).

  ENDMETHOD.

  METHOD update_familymember.

    "データベースから全項目を取得
    SELECT SINGLE * FROM zfamilymember_u
    WHERE person_id = @is_familymember-person_id
      AND member_id = @is_familymember-member_id
    INTO @DATA(ls_familymember).

    DATA index TYPE i.
    index = 3. "キーを飛ばして3番目の項目から
    DO.
      ASSIGN COMPONENT index OF STRUCTURE is_familymember_control TO FIELD-SYMBOL(<is_changed>).
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.

      IF <is_changed> = abap_true.
        "clientつきの構造のため、indexを1つ進める
        ASSIGN COMPONENT index + 1 OF STRUCTURE is_familymember TO FIELD-SYMBOL(<field_upd>).
        ASSERT sy-subrc = 0.
        ASSIGN COMPONENT index + 1 OF STRUCTURE ls_familymember TO FIELD-SYMBOL(<field_current>).
        ASSERT sy-subrc = 0.
        <field_current> = <field_upd>.
      ENDIF.

      index = index + 1.
    ENDDO.

    "タイムスタンプの設定
    GET TIME STAMP FIELD ls_familymember-last_changed_at.
    lcl_person_buffer=>get_instance( )->buffer_familymember_for_update( ls_familymember ).

  ENDMETHOD.

2. Behavior Implementationクラスの実装

Behavior Implentationクラスでは、受け取ったEntityおよびコントロール構造(更新された項目にフラグがセットされたもの)をAdapterクラスのメソッドに渡します。MAPPING FROM ENTITYというステートメントは、Behavior Definitionで定義したマッピングの通りにエンティティの項目をDBの項目にマッピングしてくれます。

Behavior Definitionでのマッピングは以下のようになっています。control ZSPerson_X_uを指定することにより、コントロール構造のフラグ(00 or 01)をbooleanに変換することができます。

  mapping for ZPERSON_U control ZSPerson_X_u
  {
    PersonID = PERSON_ID;
    FirstName = FIRST_NAME;
    LastName = LAST_NAME;
    Email = EMAIL;
    Birthday = BIRTHDAY;
    Status = STATUS;
    CreatedBy = CREATED_BY;
    CreatedAt = CREATED_AT;
    LastChangedBy = LAST_CHANGED_BY;
    LocalLastChangedAt = LOCAL_LAST_CHANGED_AT;
    LastChangedAt = LAST_CHANGED_AT;
  }

マッピングの結果は以下のようになります。
image.png

Person

zbp_i_person_u>lhc_person
  METHOD update.
    DATA person_u TYPE zperson_u.
    DATA person_ux TYPE ZSPerson_X_u.
    data person_control type zif_person_adapter=>ts_person_control.

    LOOP AT entities ASSIGNING FIELD-SYMBOL(<person>).
      person_u = CORRESPONDING #( <person> MAPPING FROM ENTITY ).
      person_ux = CORRESPONDING #( <person> MAPPING FROM ENTITY ).
      person_control = CORRESPONDING #( person_ux ).
      person_control-person_id = <person>-PersonID.
      zcl_person_adapter=>get_instance(  )->update_person(
        EXPORTING
          is_person         = person_u
          is_person_control = person_control
      ).

    ENDLOOP.

  ENDMETHOD.

Family Member

zbp_i_familymember_u>lhc_familymember
  METHOD update.
    DATA familymember_u TYPE zfamilymember_u.
    DATA familymember_ux TYPE ZSFamilyMember_X_u.
    data familymember_control type zif_person_adapter=>ts_familymember_control.

    LOOP AT entities ASSIGNING FIELD-SYMBOL(<member>).
      familymember_u = CORRESPONDING #( <member> MAPPING FROM ENTITY ).
      familymember_ux = CORRESPONDING #( <member> MAPPING FROM ENTITY ).
      familymember_control = CORRESPONDING #( familymember_ux ).
      familymember_control-person_id = <member>-PersonID.
      familymember_control-member_id = <member>-MemberID.
      zcl_person_adapter=>get_instance(  )->update_familymember(
        EXPORTING
          is_familymember         = familymember_u
          is_familymember_control = familymember_control
      ).
    ENDLOOP.

  ENDMETHOD.

動作確認

変更前の状態は以下のようになっています。
image.png
以下の項目を更新して保存します。
image.png
更新されました。
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?