SAP Cloud PlatformでカスタムFioriアプリを作ってODataと接続する-SAPUI5でのOData呼び出し処理

## 目的
[Fioriデザイン](https://experience.sap.com/fiori-design-web/)なフロントエンドを実現するSAP UI5フレームワークを使った新規アプリケーションを作る
FioriアプリケーションをSAP Cloud Platform上のHANADBで作成したODataと接続する

####SAPUI５アプリのOData接続設定
下記の記事のつづきから
設定したODataサービスを使用する
https://qiita.com/yonekura-h/items/abc67f32c318097c0ecc

##前提
####開発環境
SAP Cloud Platformのtrial環境（無償版）を利用する
https://account.hanatrial.ondemand.com/

####ODataサービスの公開
下記ブログを参考にODataサービスを作成
https://blogs.sap.com/2018/07/13/sap-cp-trial%E7%92%B0%E5%A2%83%E3%81%AEhana-db%E8%A8%AD%E5%AE%9A/

#####参考
ODataサービスの使い方は下記参考に
https://qiita.com/yonekura-h/items/29db429d91bbcc31edc4


## ODataからデータを取得する
プロジェクトにODataの接続設定がされている前提でコーディングしていく
まだ接続設定してない場合は以下参考に
https://qiita.com/yonekura-h/items/abc67f32c318097c0ecc

作成したプロジェクトの`webapp/controller/sample.controller.js`を編集する


```javascript:webapp/controller/sample.controller.js
sap.ui.define([
	"sap/ui/core/mvc/Controller"
], function (Controller) {
	"use strict";

	return Controller.extend("sample.odataConnect.controller.sample", {
		onInit: function () {
			this._getMakerData();
		},
		_getMakerData: function(){
			// oDatav2サービスに対応したoDataModelを定義
			var oModel = new sap.ui.model.odata.v2.ODataModel("/Sample/demo/demo.xsodata");
 
			// manifest.jsonにoDataModelの定義がある場合はこちら
			var oModel = this.getView().getModel("demoService");
			// "demoService"はmanifest,jsonでsap.ui5 -> modelsに記載したKey名

			// oDataリクエスト時のパラメータを作成
			var oFilter = new sap.ui.model.Filter('ID', 'GT', 0);
			var oSorter = new sap.ui.model.Sorter("ID", true);
			var mParam = {"$select" : "ID,NAME","$top":10};

			// oDataサービスにリクエスト（GET）
			oModel.read(
				"/makerdata",  // sPath ← oDataサービスで呼び出すエンティティを指定
				{
					// urlParameters ← （Filter/Souter以外の）リクエストパラメータ指定
					"urlParameters":mParam,  
					// $filter条件を指定（Where句に相当）
					"filters": [oFilter],
					// $orderby条件を指定（OrderBy句に相当）
					"sorters": [oSorter],
					// 成功したときの処理を定義
					"success": function(oData, oResponse){
									//results:{...}の形式でデータを取得可能
									console.log(oData);
								}
					// 失敗したときの処理を定義
					"error": function(oError){
									//リクエスト処理のエラーなどを取得可能
									console.log(oError);
								}
				}
		
			);
		}
	});
});
```

とりあえず初期表示時に`/demo/demo.xsodata`からメーカーのデータを取得するようにしてみる
このアプリケーションをWebIDE上で実行するとconsoleに下記が表示される
<img width="992" alt="スクリーンショット 2019-03-04 16.05.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/159467/1e52db05-f218-dbb9-ea32-453ea13b660f.png">

使用しているクラスのリファレンスは以下
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.odata.v2.ODataModel

sap.ui.model.odata.v2を利用してSelectのクエリを実行している
上記のコードの内容説明↓

###モデルの定義

```javascript
var oModel = new sap.ui.model.odata.v2.ODataModel("/Sample/demo/demo.xsodata");
```
この部分で `/Sample/demo/demo.xsodata` への接続設定をもった `sap.ui.model.odata.v2.ODataModel` インスタンスを作成している

oDataModelの設定は`manifest.json`での定義が可能
dataSourceとしてサービスを登録し、modelsプロパティの配下でODataModelの設定を記載がある場合は
Component.js実行時にアプリケーション全体で利用可能な形でインスタンス化、Bindすることができる

```javascript:webapp/manifest.json
    "sap.app": {
        // 省略
        "dataSources": {
            "demo.xsodata": {
                "uri": "/Sample/demo/demo.xsodata/",  // ←この部分がODataサービスのパス
                "type": "OData",
                "settings": {
                    "localUri": "localService/metadata.xml"
                }
            }
        }
    },
```

```javascript:webapp/manifest.json

  "sap.ui5": {
        // 省略
    "models": {
      "i18n": {
        "type": "sap.ui.model.resource.ResourceModel",
        "settings": {
          "bundleName": "sample.odataConnect.i18n.i18n"
        }
      },
      "demoService": {
          "type": "sap.ui.model.odata.v2.ODataModel",
          "settings": {
              "defaultOperationMode": "Server",
              "defaultBindingMode": "TwoWay",
              "defaultCountMode": "Request",
              "preload": true
          },
          "dataSource": "demo.xsodata" // ← dataSourcesで定義したODataサービスの情報を指定
      }
    },
```

そのためControllerファイルで都度インスタンス化せず、以下の記載でBindされた oDataModel へアクセスできる

```javascript
var oModel = this.getView().getModel("demoService");
// "demoService"はmanifest,jsonでsap.ui5 -> modelsに記載したKey名
```


###リクエストパラメータの設定

```javascript
var Filter = new sap.ui.model.Filter('ID', 'GT', 0);  // ←WHERE句
var Sorter = new sap.ui.model.Sorter("ID", true);     // ←ORDER BY句
var Param = {"$select" : "ID,NAME","$top":10};        // ←その他のパラメーター
```

WHERE句・ORDER BY句はそれぞれsap.ui.model.Filterやsap.ui.model.Sorterを
使う必要がある

* Filter
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.Filter

* Sorter
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.Sorter

この２つは定義したモデルのreadメソッドを使う際にそれぞれfilters・sortersに配列にして渡すことで
複数条件の設定が可能

その他のパラメーターを指定するときはurlParametersにJSONを渡す
どういうパラメーターがあるのかは下記のODataリファレンス参照
https://www.odata.org/getting-started/basic-tutorial/#queryData

今回のサンプルテーブルは項目がIDとNAMEしかなかったので条件がID>０と意味のないものになってます。。

###readメソッド
メソッドのリファレンスはこちら
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.odata.v2.ODataModel/methods/read


* 呼び出すEntitySetの指定（sPath部分）
* 任意でリクエストパラメーターを指定（urlParameters,filters,sorters部分）
* 成功時(失敗時)の処理を定義（success, error部分）

を指定している

```javascript
			// oDataサービスにリクエスト（GET）
			oModel.read(
				"/makerdata",  // sPath ← oDataサービスで呼び出すエンティティを指定
				{
					// urlParameters ← （Filter/Souter以外の）リクエストパラメータ指定
					"urlParameters":Param,  
					// $filter条件を指定（Where句に相当）
					"filters": [Filter],
					// $orderby条件を指定（OrderBy句に相当）
					"sorters": [Sorter],
					// 成功したときの処理を定義
					"success": function(oData, oResponse){
									//results:{...}の形式でデータを取得可能
									console.log(oData);
								}
					// 失敗したときの処理を定義
					"error": function(oError){
									//リクエスト処理のエラーなどを取得可能
									console.log(oError);
								}
				}
		
			);
```
oModelが持つODataサービス情報をもとに、
 readメソッドの引数に設定されたパラメータをもってGETリクエストを送信、ODataの指定したEntityからデータ取得を行っている

## 取得データを画面に表示する
ODataからデータが取得できたので画面に表示する
上記コードでは取得したデータをコンソールに出力しているだけなので、
Viewファイルで使えるようにデータモデルを登録する

`_getMakerData`の関数を編集

```javascript:webapp/controller/sample.controller.js
sap.ui.define([
	"sap/ui/core/mvc/Controller",
	"sap/ui/model/json/JSONModel"    //←追加
], function (Controller,JSONModel) {   //←JSONModel 追加
	"use strict";

	return Controller.extend("sample.odataConnect.controller.sample", {
		onInit: function () {
			this._getMakerData();
		},
		_getMakerData: function(){
			var oView = this.getView();    //←追加
			this.oModel = new sap.ui.model.odata.v2.ODataModel("/Sample/demo/demo.xsodata"); // /DEMO←manifest.jsonに登録したサービス名
			var Filter = new sap.ui.model.Filter('ID', 'GT', 0);
			var Sorter = new sap.ui.model.Sorter("ID", true);
		        var Param = {"$select" : "ID,NAME","$top":10};
			this.oModel.read(
				"/makerdata",  
				{
					"urlParameters":Param,
					"filters": [Filter],
					"sorters": [Sorter],
					"success": function(oData, oResponse){
									//results:{...}の形式でデータを取得可能
									// console.log(oData);
									oView.setModel(new JSONModel(oData),"makerdata");    //←追加
								}
				}
		
			);
		}
	});
});
```

ODataリクエストの成功時に取得したデータを以下のコードで`makerdata`という名称で登録している

```javascript
oView.setModel(new JSONModel(oData),"makerdata");

```

登録した`makerdata`を使ったTableを`sample.view.xml`に作る

```xml:webapp/view/sample.view.xml
<mvc:View controllerName="sample.odataConnect.controller.sample" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m">
	<Shell id="shell">
		<App id="app">
			<pages>
				<Page id="page" title="{i18n>title}">
					<content>
						<Table 
							items="{path:'makerdata>/results'}"
							class="sapUiNoContentPadding"
							id="sampleTable"
							>
							<columns>
								<Column >
									<Text text="ID"/>
								</Column>
								<Column >
									<Text text="NAME"/>
								</Column>
							</columns>
							<items>
								<ColumnListItem>
									<cells>
										<Text text="{makerdata>ID}"></Text>
										<Text text="{makerdata>NAME}"></Text>
									</cells>
								</ColumnListItem>
							</items>
						</Table>	
						
					</content>
				</Page>
			</pages>
		</App>
	</Shell>
</mvc:View>
```

プロジェクトの自動生成で作成されたファイルの\<content\>内に\<Table\>タグを追加している
sap.m.Tableについては以下のリファレンス参照
https://sapui5.hana.ondemand.com/#/api/sap.m.Table


####XMLViewファイルでのデータバインド
分かりづらいのは下記の`items`部分

```xml
<Table 
    items="{path:'makerdata>/results'}"
    class="sapUiNoContentPadding"
    id="sampleTable"
    >
```

`"{path:'モデル名>/results'}"`という書き方になっている
`/results`なのはODataで取得したデータがresults:{...}の形式となっているため
`/`以降は添字の指定なので、`/key1/key2`という指定が可能

今回はモデル登録を`makerdata`という名称にしたので、
`{path: 'makerdata>/results'}`となっている
仮に

```javascript
oView.setModel(new JSONModel(oData));

```

というコードだった場合は`{path: '/results'}`となる

また、`items`でモデル名を指定した\<Table\>タグ内、\<cells\>タグ配下の指定では`{makerdata>ID}`となる
カラム名の前にモデル名を指定する必要がある

上記のコードでできる画面は↓
<img width="1440" alt="スクリーンショット 2019-03-04 17.15.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/159467/0b3224e5-e9f7-d7ef-4b97-aec711b1aa37.png">

ODataサービス経由でHANA DBのデータを取得し画面表示ができている

##さいごに
SAP UI5で作るFioriアプリでODataを参照するアプリケーションの作成した