FDBatchMove を使って RESTで取得した JSON データをデータベースに書き込む

これは [Delphi Advent Calendar 2018](https://qiita.com/advent-calendar/2018/delphi) の 21 日目の記事です

[REST デバッカを使って REST API から JSON データを取得する記事](https://qiita.com/CYonezawa/items/e20c3018c6eb6e1200a0)を以前書きました
この取得した JSON データは、[TFDMemTable](http://docwiki.embarcadero.com/Libraries/Tokyo/ja/FireDAC.Comp.Client.TFDMemTable) というインメモリの DataSet に格納されています
既にデータセットの形でデータが存在しているので、このデータを [TFDBatchMove](http://docwiki.embarcadero.com/Libraries/Tokyo/ja/FireDAC.Comp.BatchMove.TFDBatchMove)
を使って、一気に InterBase のテーブルにデータとして書き込むということを行ってみました

## TFDBatchMove って何
通称 BatchMove
異なる種類のデータを移送する仕組みです
移送元、移送先で扱える標準の Reader/Writer として、テキスト・データセット・SQL が用意されています
ざくっとしたイメージは
![batchmove.png](https://qiita-image-store.s3.amazonaws.com/0/164551/23572d76-bbb4-99b6-1b00-881eb6d3f3ae.png)
な感じです

たとえば

- 異種データベース間でデータを流す
- データベース上のデータをテキスト形式に変換

などの用途に使用できる便利な機能です

## Delphi で作ってみる
Delphi 10.2.3 Tokyo Community Edition を使用しています (10.3 Rio でも同様に作成できます)
VCL でも FireMonkey でも作れます (この記事では FireMonkey で作りました)
JSON データを読み込むところまでは [Delphi Community Edition Meet up ! - REST 編](https://qiita.com/CYonezawa/items/e20c3018c6eb6e1200a0) をご参照ください

### TFDMemTable に読み込んだデータセットは必要なフィールドだけに絞ってしまう
全部のフィールドデータは必要ないので、TFDMemTable 上で必要なフィールドだけに絞ってしまいます
今回は
id, event_id, start_time, end_time, title, subtitle, content, act 
の8つのフィールドに絞ります

手順ですが
  1. 設計画面上の FDMemTable をマウスでダブルクリックします
  2. フィールドエディタが表示されます
  3. フィールドエディタ上で、マウスの右ボタンをクリックします
  4. 表示されたポップアップメニューより「すべてのフィールドを追加」を選択します![batch01.png](https://qiita-image-store.s3.amazonaws.com/0/164551/801db2e1-75fc-f1da-f21a-effa1e304a81.png)
  5. 不要なフィールドをマウスで選択して Delete キーを押して削除します![batch02.png](https://qiita-image-store.s3.amazonaws.com/0/164551/e3f6f0b1-5aa3-f96a-08af-9c8f96af873c.png)

で絞り込みます

### データベースにも同じ構造のテーブルを作っておく
TFDMemTable で絞り込んだ各フィールドの情報を見ると、すべて TWideStringField 長さ 255 で定義されています
今回は InterBase 側のテーブルも、同じフィールド名 (id, event_id, start_time, end_time, title, subtitle, content, act) で varchar 255 で定義しちゃいます
テーブル名は、restTable としました

### FireDAC を使って InterBase のテーブルを参照する
IDE の右上にあるプロジェクトマネージャのタブをクリックして、データエクスプローラを表示します
データエクスプローラで、流し込む先のデータベースへの接続設定を行い、接続できることを確認します
定義済みのテーブルをデータエクスプローラからドラッグ＆ドロップしてフォーム上に FDConnection と FDQuery を配置します
![batch03.png](https://qiita-image-store.s3.amazonaws.com/0/164551/d5c3dc61-1e79-1846-16dd-15477d706517.png)
FDQuery の Enable は True にしておき、データベースと接続しておきます

### Reader と Writer コンポーネントにデータセットを設定する
ツールパレットから、TFDBatchMove, TFDBatchMoveDataSetReader, TFDBatchMoveDataSetWriter をドラック＆ドロップで配置します (名前が長いので、以下 BatchMove, Reader, Writer とします)
オブジェクトインスペクタで FDBatchMoveDataSetReader 側の DataSet プロパティを FDMemTable1 に設定します
![batch04.png](https://qiita-image-store.s3.amazonaws.com/0/164551/eb09e1a7-72f9-386f-ad76-23918313c153.png)
オブジェクトインスペクタで FDBatchMoveDataSetWriter 側の DataSet プロパティを RestTableTable(FDQuery) に設定します
![batch05.png](https://qiita-image-store.s3.amazonaws.com/0/164551/440766a1-adaf-01ab-94d7-ab5cdf5a59da.png)

### BatchMove コンポーネントに Reader と Writer コンポーネントを関連付ける
実は Reader と Writer が１つずつであれば、自動的に設定されます
Reader および Writer が複数ある場合はオブジェクトインスペクタ上で使用する Reader, Writer を設定します
![batch06.png](https://qiita-image-store.s3.amazonaws.com/0/164551/4b4a1afa-c81c-3958-c338-747513bc8b96.png)

これで設定は終了です

### 今回の設計画面
このサンプルでは、分かりやすいように TStringGrid と TButton をそれぞれ２つ配置しています
各 StringGrid は FDMemTable および表示用の FDQuery(データエクスプローラから、もうひとつ restTable を置く)と Visual Live Binding を使って関連付けを行っています
![batch18.png](https://qiita-image-store.s3.amazonaws.com/0/164551/d196253b-0308-0dfb-59f9-19b20c2d1f4a.png)


### データベースへ書き込む
REST API から読み込んだデータをそのまま BatchMove で InterBase のテーブルに流し込みます

REST API から JSON データを読み込む側は、Button の OnClick イベントに次のコードを記載します

```pascal
  RESTRequest1.Execute;  // REST API 経由でデータを読み込む
```

読み込んだ JSON データを InterBase に流し込む側は、Button の OnClick に次のコードを記載します
 
```pascal
  FDBatchMove1.Execute;  // Reader -> BatchMove -> Writer にデータを流し込みます
  FDQuery1.Open;         // 流し込んだデータを下の StringGridに表示する
```

注意: エラー処理は行なっていません

### 実行してみる
Get ボタンを押すと、REST API で JSON データが読み込まれ、BatchMove ボタンを押すと、そのデータが InterBase 側に流し込まれて、StringGrid上に表示されます
![batch19.png](https://qiita-image-store.s3.amazonaws.com/0/164551/80eff0ee-eb99-baa4-56d6-e2f752238f0b.png)
![batch20.png](https://qiita-image-store.s3.amazonaws.com/0/164551/573a81ad-5cbd-4f6f-316d-29f4f5ee42fe.png)
![batch21.png](https://qiita-image-store.s3.amazonaws.com/0/164551/5267a61e-1ab4-05f8-3b3a-df08a8051664.png)


## InterBase の操作
今回使用した InterBase 側の操作

- サーバーの起動
- データベースの作成
- テーブルの作成

をまとめておきます

### InterBase Server の起動
InterBase を使うには、最初に InterBase Server を起動しておく必要があります
Windows のメニューから InterBase Server Manager を起動します
![batch01_1.png](https://qiita-image-store.s3.amazonaws.com/0/164551/726d3a8c-508c-f42a-932d-972a4a42f16d.png)

"InterBase サーバーの状態"の横に「停止中」と赤文字で表示されている場合は、サーバーが停止していますので [起動] のボタンをクリックしてサーバーを起動します
![batch02.png](https://qiita-image-store.s3.amazonaws.com/0/164551/5f988902-ed38-cdef-975d-c0e83516094f.png)

"InterBase サーバーの状態"の横の文字が、緑色で「動作中」と表示されていれば OK です
![batch03.png](https://qiita-image-store.s3.amazonaws.com/0/164551/63fd6b5f-78b8-8229-cb1e-d8b5844805b7.png)

*もし、エラーが表示されて起動できない場合は、ライセンスの登録状況を確認（大抵が必要なライセンスが無かったり、間違った認証を行ったりしているのが原因）して、それでも分からなければエンバカデロのインストールサポートに問い合わせましょう*

### データベースの作成
Windows のメニューから IBConsole を起動します
![batch01_2.png](https://qiita-image-store.s3.amazonaws.com/0/164551/0be486de-5ca1-f53b-0424-46159af25a31.png)

メニューの [データベース|データベースの作成] を選択します
![batch04.png](https://qiita-image-store.s3.amazonaws.com/0/164551/2a843eb7-b8f7-856a-bd0e-62613c867774.png)

ファイル名など必要な情報を設定して [OK] ボタンをクリックするとデータベースファイル(.ib/.gdb)が作成されます
![batch05.png](https://qiita-image-store.s3.amazonaws.com/0/164551/e18f97a8-3ea5-7944-529f-14cf477617bd.png)

### テーブルの作成
IBConsole でデータベースとの接続が確立している状態で、テーブルを作成します
テーブルエディタや、SQL(DDL)文でテーブルを作成できます

##### テーブルエディタを使って定義する手順
1. データベースのツリー構造を展開して、テーブルを選択します
2. 右側の "データベース" タブの画面内で、マウスの右ボタンをクリックします
3. 表示されたポップアップメニューから「作成」を選択します ![batch06.png](https://qiita-image-store.s3.amazonaws.com/0/164551/2b5da389-a94a-4db9-cc24-f61a5cf3313e.png)
4. テーブルエディタが表示されますので、テーブル名を入力します
5. [フィールドの追加]ボタンをクリックしてフィールドを追加します
![batch09.png](https://qiita-image-store.s3.amazonaws.com/0/164551/b7b1e6ea-51e5-4e49-8835-75d5215a943f.png)

##### SQL(DDL) を使って定義する手順
1. メニューより [ツール|対話型SQL]を選択します ![batch08.png](https://qiita-image-store.s3.amazonaws.com/0/164551/f62a3482-da00-68ef-6540-e6fe15360a53.png)
2. ISQL(Interactive SQL)が開くので、テーブルを定義する SQL文(DDL)を記述します
3. 稲妻マークのボタンをクリックすると、記述した SQL文が実行されてテーブルが作成されます
![batch07.png](https://qiita-image-store.s3.amazonaws.com/0/164551/83f5840d-2fb3-ac65-b284-30415179d88c.png)

## あとがき
この記事では、「FDBatchMove」で流しこむことをメインとしたかったので、流し込む先の InterBase 側のフィールドをすべて varchar 255 にしています