【SAPUI5】OData(6) SAPでのODataサービスの作り方 開発編-2

##概要
[前回](https://qiita.com/tami/items/f49a4a6be1ffd83cc87c)の記事では、Entity Typeの定義とODataサービスの有効化を行いました。
今回は、データを取得するためのコードを書いていきます。
※引き続き以下のページの画面ショットを引用させていただきます
[OData and SAP Netweaver Gateway. Part II. Create your first OData Service](http://www.sapyard.com/odata-and-sap-netweaver-gateway-part-ii-create-your-first-odata-service/)
[OData and SAP Netweaver Gateway. Part III. Query Options in OData Service URI](http://www.sapyard.com/odata-and-sap-netweaver-gateway-part-iii-query-options-in-odata-service-uri/)
[OData and SAP Netweaver Gateway. Part IV. Association and Navigation in OData Service](http://www.sapyard.com/odata-and-sap-netweaver-gateway-part-iv-association-and-navigation-in-odata-service/)

※OData関連の投稿一覧は以下の記事をご参照ください。
[【SAPUI5】OData(1) ODataとは](https://qiita.com/tami/items/411a226d1ea6bb25b5f1)

##ステップ
1. Entity Set（複数データ）を取得するためのメソッドを定義
2. Entity（単一データ）を取得するためのメソッドを定義
3. 明細用のメソッドを定義
4. Associationの定義

###1. Entity Set（複数データ）を取得するためのメソッドを定義
Entity Setを定義したときに、Service Implementationフォルダの配下に自動的にCreate, Deleteなどの操作が登録されてます。登録時点ではガラだけなので、これらに対して実装を登録します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/7161dc5c-9b2a-d0d8-24a0-2b6794cd3e9f.png)

"GetEntitySet(QUery)"の上で右クリックして、"Go to ABAP Workbench"を選択するとData Provider Class(DPC)の拡張クラスへナビゲートされます。このクラスは、ODataサービスを登録したときに同時に登録されたものです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/f8b48754-2394-85ab-b16c-f242ae40b714.png)

"~_GET_ENTITYSET"というメソッドを選択して、"Redefine"（再定義）を押します。（~の部分はEntity Typeが入ります）
デフォルトのコードをクリアして、コードを入力します。簡単にするために10件のデータを取得するだけです。

```abap
  SELECT * UP TO 10 ROWS FROM ekko INTO CORRESPONDING FIELDS OF TABLE et_entityset.
```

SAP Gateway Client(Tr:/IWFND/GW_CLIENT)で実行すると、10件のデータが返ってきます。
URI: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/3977618e-46f0-c7f3-2669-066b114db7dc.png)

###2. Entity（単一データ）を取得するためのメソッドを定義
続いて、1件のEntityを取得するためのメソッドを定義します。データを1件だけ取得するためには、以下のようにURIでキーを指定する必要があります。
/sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500002012’).
メソッドでは、キーを判断してデータを取得します。

さきほどと同様の手順で"GetEntity(Read)"の上で右クリックして、DPCの拡張クラスへ移動します。またはTr:SE24でクラスを直接開いてもOKです。
"~_GET_ENTITY"というメソッドを再定義します。

```abap
DATA : ls_key_tab LIKE LINE OF it_key_tab,
lv_ebeln TYPE ekko-ebeln.
 
* IT_KEY_TABに伝票番号(Ebeln)が指定されていたらその値を取得
READ TABLE it_key_tab INTO ls_key_tab
WITH KEY name = 'Ebeln'. " Case sensitive
IF sy-subrc EQ 0.
  lv_ebeln = ls_key_tab-value.
ENDIF.
 
* 1件のPOを取得
SELECT SINGLE * FROM ekko INTO CORRESPONDING FIELDS OF er_entity
WHERE ebeln = lv_ebeln.
```

it_key_tabという引数に、クエリから渡されたパラメータが入っています。
it_key_tabの中身は以下のようになっています。

| name  |value   |
|:-----|:--------|
|Ebeln |‘4500002012’|

SAP Gateway Client(Tr:/IWFND/GW_CLIENT)で実行すると、1件のデータが返ってきます。
URI: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500002012’)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/09d857a5-1c1f-f4ef-a956-31a7a74a3937.png)

GET_ENTITYメソッドが呼ばれるか、GET_ENTITYSETが呼ばれるかはSAP Netweaver Gatewayが判断してくれます。キーを1件だけ指定した場合は、GET_ENTITYが呼ばれます。

###3. 明細用のメソッドを定義
同様にして、POItem取得用のメソッドを定義します。サンプルコードは以下のようになります。
####GET_ENTITYSET

```abap
DATA: 
  ls_key_tab TYPE /iwbep/s_mgw_name_value_pair,
  lv_ebeln TYPE ebeln.
 
* キー（伝票番号）を取得
READ TABLE it_key_tab WITH KEY name = 'Ebeln' INTO ls_key_tab.
IF sy-subrc = 0.
  lv_ebeln = ls_key_tab-value.
ENDIF.
 
* キーが指定されている場合、伝票番号を指定して取得
IF lv_ebeln IS NOT INITIAL. 
  SELECT * FROM ekpo INTO CORRESPONDING FIELDS OF TABLE et_entityset
  WHERE ebeln = lv_ebeln.
ELSE.
 
* 指定されていない場合は10件の明細を取得
  SELECT * UP TO 10 ROWS FROM ekpo INTO CORRESPONDING FIELDS OF TABLE et_entityset.
 
ENDIF.
```

####GET_ENTITY

```abap
DATA: 
  ls_key_tab TYPE /iwbep/s_mgw_name_value_pair,
  lv_ebeln TYPE ebeln,
  lv_ebelp TYPE ebelp.
 
* キー（伝票番号）を取得
READ TABLE it_key_tab INTO ls_key_tab WITH KEY name = 'Ebeln' .
IF sy-subrc = 0.
  lv_ebeln = ls_key_tab-value.
ENDIF.
 
* キー（明細番号）を取得
READ TABLE it_key_tab INTO ls_key_tab WITH KEY name = 'Ebelp' .
IF sy-subrc = 0.
  lv_ebelp = ls_key_tab-value.
ENDIF.
 
* PO明細の1行を取得
SELECT SINGLE * FROM ekpo INTO CORRESPONDING FIELDS OF er_entity
WHERE ebeln = lv_ebeln
AND ebelp = lv_ebelp.
```
明細の場合、キーが伝票番号と明細番号の2つになります。それぞれをit_key_tabから取得します。

###4. Associationの定義
ここで登場するのはAssociation, Navigation Property, Association Setです。

####Association
AssociationはEntity同士の関係を定義するものです。POの場合、ヘッダの伝票番号と明細の伝票番号でひもづいていて、ヘッダ：明細は1:Nになる、という関係を持っています。

####Navigation Property
Navigation PropertyはあるEntityからほかのEntityへリンクする際、どのAssociationを使うのかを定義するものです。以下の図に示すように、Navigation PropertyはEntity Setの属性です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/f9d89022-5c2c-6902-df7a-ba27ecd42bda.png)

####Association Set
AssociationがEntity同士の関係を表すのに対して、Association SetはEntity Set同士の関係を表します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/6afe4772-9a9c-af7e-89af-3bf4b87e8d4b.png)

####実装
Associationフォルダの上で右クリックし、"Create"を選択します。
以下の情報を入力します。

- Associationの名前
- ひもづけるEntityの名前（左側が主、右側が従）
- カーディナリティ
- Navigation Propertyの名前（Create related Navigation Propertyにチェック）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/6ea6361d-356d-15dd-7241-d3b080782da9.png)

次の画面でEntity同士をひもづけるキーを入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/9f44a58c-9854-e0fd-dc62-937426b741f1.png)

次の画面ではAssociation Setの名前を入力します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/3b54eb4c-047d-3264-24fe-97bbb5001f59.png)

Navigation Property, Association, Association Setが以下のように登録されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/16bd177e-9290-5594-c6d2-8a7201668545.png)

ODataサービスを変更したら、都度有効化します。

##metadataを確認
SAP Gateway Clientでmetadataを見てみると、Navigation Property, Association, Association Setが確認できます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/07d868bf-37e1-1167-6d13-cc8a8901bfa4.png)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/f1d71f41-8900-6aa8-08ee-751f43473645.png)

##データを取得してみる
Associationを定義したことにより、クエリの結果がどのように変わるか見てみましょう。
URI: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500002012’)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/d9fcd754-47d1-6161-ff16-5b4ca199c28b.png)

結果にHeadToItemNavへのリンクが追加されています。Navigation Propertyを設定したことにより、「Itemにナビゲーションできますよ」という情報が返ってきたのです。
次に、その情報そのままURIとして入力してみます。
URI: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500002012’)/HeadToItemNav
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/afb8a361-05d4-5784-15ff-acbbf6910a29.png)

すると、ヘッダにひもづく明細データが返ってきます。ここで返ってくるのは明細データだけで、ヘッダは返ってきません。
ヘッダと明細両方返したい場合は、クエリオプション**$expand**を使います。（クエリオプションについては[こちら](https://qiita.com/tami/items/181cabc4cd8c51ce87b2)を参照）

URI: /sap/opu/odata/sap/ZGW_PO_SRV/POHeaderSet(‘4500001729’)?$expand=HeadToItemNav
![image.png](https://qiita-image-store.s3.amazonaws.com/0/276021/6c06d35f-e17b-5130-c1d0-ba68089b940d.png)

##まとめ
- 単一データを取得するのか、複数データを取得するのかによって異なるメソッドの実装が必要
- メソッドはDPCの拡張クラスに実装する
- Associationで2つのEntityの関連を定義する

##関連記事
[OData(5) SAPでのODataサービスの作り方 開発編-1](https://qiita.com/tami/items/f49a4a6be1ffd83cc87c)
[OData(7) ODataを使ったSAPUI5アプリケーションの作り方 準備編](https://qiita.com/tami/items/510a28655ee1af6254ea)