作成する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_IDはNULLとなり、列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コードとして以下を記述します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
begin | |
case | |
when :APEX$ROW_STATUS = 'C' then | |
if :CLASS_ID is null then | |
/* | |
* 対話グリッドの:CLASS_IDがNULLのときは、フォーム上でクラスが新規作成されている。 | |
*/ | |
insert into ebaj_mdf_members(class_id, member_name) values(:P2_ID, :MEMBER_NAME) returning id into :ID; | |
else | |
insert into ebaj_mdf_members(class_id, member_name) values(:CLASS_ID, :MEMBER_NAME) returning id into :ID; | |
end if; | |
when :APEX$ROW_STATUS = 'U' then | |
/* UPDATEの場合、CLASS_IDが未設定ということはないはず */ | |
update ebaj_mdf_members set member_name = :MEMBER_NAME where id = :ID; | |
when :APEX$ROW_STATUS = 'D' then | |
delete from ebaj_mdf_members where id = :ID; | |
end case; | |
end; |
以上で実装は完了です。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/sample-master-detail-form-with-grid.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完