2024年10月22日火曜日

マスター表の編集フォームにディテール表を編集する対話グリッドを配置する

マスター表にあるレコードを編集するフォームに、そのレコードに紐づく子レコードを同時に編集する対話グリッドを配置してみます。

作成するAPEXアプリケーションは以下のように動作します。


以下のクイックSQLのモデルより、マスター・ディテール関係を持つ簡単な表EBAJ_MDF_CLASSESとEBAJ_MDF_MEMBERSを作成します。マスター表のEBAJ_MDF_CLASSESにはクラスの名前、EBAJ_MDF_MEMBERSはクラスに所属するメンバーの名前を保存します。
# prefix: ebaj_mdf
classes
    class_name vc80 /nn

members
    class_id /fk classes /nn /cascade
    member_name vc80 /nn
表EBAJ_MDF_MEMBERSの列CLASS_IDにはマスター表への参照制約を作成し(/fk classes)、また、NOT NULL制約およびマスター表の行が削除される際に、紐づいている子レコードを削除するオプション(/cascade)を付けています。

レビューおよび実行をクリックし、表の作成までの一連の作業を実行します。


 表EBAJ_MDF_CLASSESとEBAJ_MDF_MEMBERSが作成されます。


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

作成するアプリケーションの名前Master Detail Form with Gridとします。デフォルトのホーム・ページを削除し、表EBAJ_MDF_CLASSESソースとした、フォーム付き対話モード・レポートのページを追加します。

以上で、アプリケーションの作成をクリックします。


アプリケーションが作成されます。

対話グリッドは、フォームとして作成されたページに作成します。


ページ・デザイナでフォームのページを開き、新規に対話グリッドのリージョンを作成します。

識別名前Membersとします。タイプ対話グリッドソース表名として、ディテール表であるEBAJ_MDF_MEMBERSを指定します。

フォームとして開かれた親レコードの主キーの値は、ページ・アイテムP2_IDに保持されています。対話グリッドに表示する(つまり編集対象となる)行を、親レコードに紐づくメンバーに限定するため、WHERE句class_id = :P2_IDという条件を記述します。


対話グリッドの列CLASS_IDを選択します。

対話グリッドでは親レコードに紐づいた子レコードだけを表示するので、列CLASS_IDを表示する必要はありません。ここではタイプ非表示に変更します。次に対話グリッドで新規行を追加するときの列CLASS_IDのデフォルト値が、ページ・アイテムP2_IDの値になるように、デフォルトを設定します。


対話モード・レポートの属性を開き、編集オンにします。ツール・バーコントロールより保存ボタンチェックを外し、対話グリッド単体での編集を不可として、つねにフォームのボタンから作成変更の適用削除が実施されるようにします。


プロセス・ビューを開き、対話グリッドの処理を行うプロセスMembers - 対話グリッド・データの保存ダイアログを閉じるより上に配置します。プロセスが呼ばれるより先にダイアログが閉じてしまうと、表EBAJ_MDF_MEMBERSへの操作が行われません。


ここまでの実装で、親レコードの作成、更新、削除とそれに紐づく子レコードの作成、更新、削除は実施できます。しかし、親レコードの作成と子レコードの作成を同時に行うと、ORA-01400(NOT NULL制約の違反)が発生します。

CLASS_IDデフォルト値としてページ・アイテムP2_IDを設定していますが、フォームのページが開いた時点では、表EBAJ_MDF_CLASSESに行は作成されていません。そのため、ページ・アイテムP2_IDNULLとなり、列CLASS_IDデフォルト値もNULLになります。列CLASS_IDにNOT NULL制約を付けていない場合は、対話グリッドに設定した行は表EBAJ_MDF_MEMBERSに挿入されますが、CLASS_IDがNULLであるため親レコードと紐づかない、表示も編集もできないレコードになってしまいます。


フォームを処理するプロセスの設定挿入後に主キーを返すオンの場合、プロセス終了時に主キー・アイテムに、新たに作成されたレコードの主キーの値が設定されます。今回の例では、ページ・アイテムP2_IDに主キーの値が設定されます。


後続の対話グリッドの処理を列CLASS_IDの値がNULLの場合に、代わりにページ・アイテムP2_IDの値を使うように、PL/SQLコードによる処理に変更します。

設定ターゲット・タイプPL/SQLコードに変更し、挿入/更新/削除するPL/SQLコードとして以下を記述します。



以上で実装は完了です。

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

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