2020年8月11日火曜日

Oracle APEXでJSONを使う

 Oracle APEXでアプリケーションを作成するには、必ずではないですが、データベースに表がある、ということを前提としています。Oracle APEXを開発している部門を統括しているSenior Vice PresidentのMike Hichwaのツイートにあるように、

With a strong data model the application almost write itself.

であり、Oracle APEXは単にUIを作るためのツールというより、データモデル(スキーマ定義といってもよい)からUIを自動的に生成するツールとして作られています。

とはいえ、データモデルを作る、または、スキーマを定義する、というのは大変な作業であり、さらに言うと、現在あるすべての要件を盛り込むことや、将来発生しうる要件を考慮すること、そういったことができるのかどうかもわかりません。

Oracle DatabaseはJSON形式のドキュメントを列に保存することができます。スキーマの定義を厳密に行えないケースに対応するために、JSONを使うことができます。これから、Oracle APEXでJSONを扱う方法について紹介します。

Oracle DatabaseでJSONを扱う方法を、OracleのBeda HammerschmidtがLIve SQLYouTubeで紹介しています。タイトルはUsing JSON for FlexfieldsまたはUsing JSON to Implement Flexfieldsです。ここで使用されているEMP表の定義を少々簡単にして、Oracle APEXによるユーザー・インターフェースを開発します。

クイックSQLの以下のモデルから表FF_EMPを作成します。

# prefix: ff
emp
    empno    num /pk
    ename    vc50
    job      vc50
    hiredate
    sal      num
    flex     json
JSON形式のドキュメントを保存する列は、flexとして定義されています。

SQLの生成SQLスクリプトを保存レビューおよび実行を順次クリックします。


スクリプト・エディタが開きます。

列FLEXの定義をCLOBからBLOBに変更します。また、Autonomous Databaseであればformat osonの指定を付加します。

    flex                           blob check (flex is json format oson)

JSONのデータはCLOBとしても保存可能ですが、日本語を含むデータをCLOBで保存すると内部的にUTF-16のエンコーディングに変換されるため効率が良くありません。

このスクリプトを実行すると、表FF_EMPが作成されます。


作成された表FF_EMPを元に、アプリケーションを作成します。

アプリケーションの作成を実行します。確認画面が開くので、そこでもアプリケーションの作成をクリックします。


アプリケーション作成ウィザードが起動します。

アプリケーションの名前JSON flexfieldの実装とします。フォーム付きの対話モード・レポートのページだけを使用するので、ホーム・ページは削除します。

以上でアプリケーションの作成を実行します。


これで元になるアプリケーションが作成されました。


アプリケーションを実行し、JSONを保存する列FLEXを確認します。

対話モード・レポートのページが開きます。データは未入力であるため、一行もありません。作成をクリックします。


表FF_EMPにデータを入力するフォームが開きます。列FLEXのデータ型はBLOBであるため、ファイル・セレクタがUIになっています。ファイルとしてJSONのデータが存在している場合は、そのファイルを選択すると、列FLEXへJSONデータが保存されます。


Live SQLで紹介されているように、列FLEXとして

{"shoeSize":12, "skills":["oracle", "c", "java"]}

を登録することにします。つまり、数値フィールドであるshoeSizeと、複数の値を持つskillsをフォーム画面から与え、列FLEXにJSON形式で保存します。そのデータを呼び出すときはJSON形式のデータから、shoeSizeとskillsを取り出すことになります。

ページ・デザイナでページ番号のフォームのページを開きます。

列FLEXに対応するページ・アイテムP2_FLEXを、ビルド・オプションコメント・アウトします。


ページ・アイテムP2_FLEXの代わりに、shoeSizeに対応するページ・アイテムを追加します。

名前P2_SHOESIZEとします。タイプ数値フィールドです。ラベル靴のサイズソース使用セッション・ステートの値がNULLの場合のみを設定し、セッション・ステートストレージリクエストごと(メモリーのみ)を設定します。


次に、skillsに対応するページ・アイテムを追加します。名前P2_SKILLSとします。タイプはテキスト・フィールドです。ラベルスキル(複数)、それ以外はP2_SHOESIZEと同じにします。


上記を保存し、アプリケーションを実行して修正したフォームを開くと、ファイル・セレクタの代わりに靴のサイズスキル(複数)の2つのフィールドが追加されていることを確認できます。


ページ・デザイナに戻り、列FLEXからP2_SHOESIZE、P2_SKILLSを取り出すプロセス、および、P2_SHOESIZE、P2_SKILLSを列FLEXへ保存するプロセスを作成します。

従業員番号を引数として、靴のサイズとスキルを取り出すプロシージャread_from_jsonを作成します。


プロセスを作成し、レンダリング前ヘッダーの前にあるプロセス初期化フォームFf Empの直下に配置します。

識別名前JSON読み取りタイプAPIの呼出しを選択します。設定タイプとしてPL/SQL Procedure or Functionを選択し、作成済みのプロシージャREAD_FROM_JSONが呼び出されるようにします。サーバー側の条件としてタイプアイテムはNULLではないを選択し、アイテムとしてP2_EMPNOを指定します。


パラメータp_empnop_shoesizep_skillsにはそれぞれページ・アイテムP2_EMPNOP2_SHOESIZEP_SKILLSがデフォルトで割り当てられます。


JSONから靴のサイズとスキルを読み取るプロセスを作成しました。次にそれらをJSON形式にし、書き込むプロセスを作成します。

従業員番号を引数として、靴のサイズとスキルをJSONに変換して書き込むプロシージャwrite_to_jsonを作成します。


プロセス・ビューを開きます。プロセスを作成し、プロセスプロセス・フォームEf Empの直下に配置します。

識別名前JSON書き込みタイプAPIの呼出しを選択します。設定タイプとしてPL/SQL Procedure or Functionを選択し、作成済みのプロシージャWRITE_TO_JSONが呼び出されるように設定します。サーバー側の条件としてタイプリクエストは値に含まれるを選択し、としてCREATE,SAVEを指定します。


両方のプロシージャで、Oracle Databaseが提供しているJSONを扱う機能を使用しています。

取り出しと書き込みのプロセスが登録されたので、実際にデータの入力、編集を行います。フォームを開いて、靴のサイズ(ここでは12)、スキル(ここではoracle c java)を登録して確認します。


作成をクリックしフォームを閉じた後、再度フォームを開いて設定した値を確認します。

最後の対話モード・レポートのSQLに靴のサイズとスキルを表示するよう、変更を加えます。対話モード・レポートのページを開き、ソースSQL問合せを以下に変更します。
select EMPNO,
       ENAME,
       JOB,
       HIREDATE,
       SAL,
       e.flex.shoeSize "SHOESIZE",
       e.flex.skills "SKILLS"
  from FF_EMP e


対話モード・レポートの表示は以下のようになります。


Oracle APEXでJSON形式のドキュメントを扱う方法の紹介は以上になります。

データの活用を考えたとき、スキーマとして定義できるに越したことはありませんが、そうも行かない場合は多々あるかと思います。そのような場合、JSONが扱えるのはアプリケーションを開発する側に色々なオプションを与えてくれるでしょう。

今回作成したアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/json-flexfield-in-apex.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。