2022年8月10日水曜日

セッション・ステートの保持 - メモリーとディスクの違い

 ページ・アイテムのソースセッション・ステートの保持の設定で、リクエストごと(メモリーのみ)セッションごと(ディスク)のどちらかを選んだ時の違いを、クラシック・レポートとポップアップLOVを使って説明してみます。



準備


セッション・ステートの保持の設定による動作の違いを確認するために、APEXアプリケーションを作成します。

サンプル・データセットEMP/DEPTに含まれる表EMPを検証に使用します。

SQLワークショップユーティリティサンプル・データセットを開き、EMP/DEPTインストールを実行します。言語日本語英語のどちらを選んでも作業は可能です。また、アプリケーションの作成は行いません。

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

アプリケーションの名前セッション・ステートの保持とし、ページの作成をクリックします。

作成するのはクラシック・レポートですが、とりあえず対話モード・レポートを選択します。

ページ名EMPとします。表またはビュークラシック・レポートを選択します。表またはビューとしてEMPを選択します。使用するのはクラシック・レポートのみなので、フォームを含めるチェックは入れません

ページの追加をクリックします。

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

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

ページ・デザイナにてクラシック・レポートのページ(ページ番号)を開きます。

クラシック・レポートのリージョンEmployeesに、ページ・アイテムP2_HIREDATEを作成します。識別タイプとして日付ピッカーを選択し、ラベル採用日とします。

最初はソースセッション・ステートの保持リクエストごと(メモリーのみ)とします。

リージョンEmployeesのソースのWHERE句として hiredate > :P2_HIREDATE を記述します。送信するページ・アイテムは指定しません。


リージョンEmployeesに、ポップアップLOVのページ・アイテムを作成します。

識別名前P2_ENAMEタイプポップアップLOVとします。ラベル従業員とします。LOVタイプSQL問合せを選択し、SQL問合せとして、クラシック・レポートのソースと同等のSELECT文を記載します。

select ename d, empno r from emp where hiredate > :P2_HIREDATE

追加値の表示OFFとします。

ソースセッション・ステートの保持リクエストごと(メモリーのみ)を選択します。今回のアプリケーションでは、ページ・アイテムP2_ENAMEの値が参照されることはないため、セッション・ステートの保持セッションごと(ディスク)でもかまいません。どちらを設定しても良い場合は、サーバーへの負荷の少ないリクエストごと(メモリーのみ)を選びます。

このレポートを呼び出すボタンを、ホーム・ページに作成します。

ページ・デザイナホーム・ページを開きます。

ページ・アイテムP1_HIREDATEを作成します。識別タイプ日付ピッカーラベル採用日とします。ソースセッション・ステートの保持リクエストごと(メモリーのみ)を選択します。


クラシック・レポートのページに移動するボタンを作成します。

識別ボタン名B_SUBMITラベル送信とします。動作アクションページの送信とします。


ページが送信された後にクラシック・レポートのページに遷移するために、ブランチを作成します。

左ペインでプロセス・ビューを開きます。

ブランチを作成し、識別名前レポートを開くとします。動作タイプとしてページまたはURL(リダイレクト)を選択します。サーバー側の条件ボタン押下時としてB_SUBMITを選択します。


リンク・ビルダー・ダーゲットの設定です。

ターゲットタイプこのアプリケーションのページページになります。アイテムの設定名前P2_HIREDATEを選び、そのとして&P1_HIREDATE.を指定します。


以上で検証に使用するアプリケーションは完成しました。

ここまでのアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/maintain-session-state.zip

このアプリケーションを使って、検証を行います。


クラシック・レポートへの遷移にブランチを使う点について


検証に使用するアプリケーションでは、ブランチを作成してクラシック・レポートのページに遷移しています。このときボタンの動作アクションこのアプリケーションのページにリダイレクトを選択して、ページ番号2に遷移させると期待した動作にはなりません。

ボタンの動作アクションこのアプリケーションのページにリダイレクトを設定すると、ボタンはapex.navigation.redirectを呼び出します。設定されたページ・アイテムはGETリクエストの引数として、サーバーに送信されます。GETリクエストの宛先となるURLはページの生成時に引数を含めて決定され、ページが表示された後のページ・アイテムの変更がURLに反映されることはありません

簡略化すると、以下のHTML要素が生成されます。

<button onclick='apex.navigation.redirect("/ords/r/apexdev/maintain-session-state/emp?p2_hiredate=レンダリング時のP1_HIREDATEの値&session=セッションID
");'>

AタグのHREFの指定が、HTTPのGETで呼び出される動作と同じです。

動作アクションページの送信の場合は、apex.submitを呼び出します。画面上のページ・アイテムの値はPOSTリクエストの内容として、すべてサーバーに送信されます。

<button onclick='apex.submit({request: "B_SUBMIT"; validate:true});'>

formタグの内容が、HTTPのPOSTで送信される動作と同じです。

今回のボタンB_SUBMIT動作アクションを、このアプリケーションのページにリダイレクトに変更してページ番号に遷移させてみます。ページ・アイテムP1_HIREDATEはホーム・ページが表示された時点では値が無いため、採用日に何を設定してもクラシック・レポートには従業員が表示されません。

ホーム・ページが表示されたときの状況です。


採用日に値を設定し、送信ボタンを押します。


送信ボタンのURLの引数P2_HIREDATEの値は空白なので、ターゲットのページに存在するクラシック・レポートには何も表示されません。


ボタンの動作アクションとしてページの送信が選択されていると、このような結果にはなりません。


リクエストごと(メモリーのみ)の場合



ページ・アイテムP2_HIREDATEソースセッション・ステートの保持が、リクエストごと(メモリーのみ)のときの動作について確認してみます。

採用日1960/01/01を入力し、送信をクリックします。


ページ・アイテムP1_HIREDATEの値1960/01/01が、P2_HIREDATEに渡されます。

ページ・アイテムP2_HIREDATEには1960/01/01が表示されます。

ポップアップLOVP2_ENAMESQL問合せに含まれるP2_HIREDATENULLとなり、従業員は表示されません。

クラシック・レポートはP2_HIREDATE1960/01/01が割り当てられ、すべての従業員が一覧されます。


クラシック・レポートにはP2_HIREDATEに1960/01/01といった値が割り当てられるのに、ポップアップLOVはなぜNULLになるのか、その違いですが、コンポーネント自体がAjaxコールを発行してデータを取得している場合、バインド変数にページ・アイテムの値を割り当てるには、送信するページ・アイテムにそのページ・アイテムを設定する必要があります

動的アクションのリフレッシュに対応しているコンポーネントは、概ねコンポーネントの表示(HTMLの生成)とデータの取得は独立しているので、データ・ソースにバインド変数が含まれる場合は送信するページ・アイテムの設定が必要になります。

上記の設定ではクラシック・レポートで従業員の一覧が表示されています。クラシック・レポートの属性パフォーマンス遅延ロードONにすると、レポートの表示(HTMLの生成)とデータの取得が非同期で行われるようになります。


この場合、送信するページ・アイテムを設定していないと、P2_HIREDATENULLになり従業員が表示されません。


ソースの送信するページ・アイテムP2_HIREDATEを設定すると、ソースのSELECT文を実行する際にはページ・アイテムP2_HIREDATE画面上の値を取得し、サーバーに送信します。そのため、取得される従業員はつねにページ・アイテムP2_HIREDATEが評価された結果になります。


ポップアップLOVではカスケードLOVの設定があり、ここで設定したページ・アイテムは、LOVSQL問合せが実行されるときにサーバーに送信されます。

ページ・アイテムP2_ENAMEカスケードLOV親アイテムとしてP2_HIREDATEを設定することにより、ポップアップLOVでも従業員の一覧が表示されます。


これらの設定を行うことにより、クラシック・レポートおよびポップアップLOVの双方で、データ取得時にページ・アイテムP2_HIREDATEが評価されます。


多くのコンポーネントは送信するページ・アイテムの設定を含んでいます。送信するページ・アイテムによる設定では、その時点で画面に表示されている値がサーバーに渡されます。

ページ・アイテムP2_HIREDATEが変更されたときにクラシック・レポートがリフレッシュされるよう、動的アクションを作成します。

ページ・アイテムP2_HIREDATE動的アクションを作成します。名前onChange P2_HIREDATEとします。タイミングデフォルトがそのまま使えます。TRUEアクションリフレッシュ影響を受ける要素選択タイプリージョンリージョンとしてEmployeesを選択します。


採用日の値が変更されると、クラシック・レポートのリフレッシュが呼び出されます。データ・ソースとなるSELECT文が実行されるときはつねに送信するページ・アイテムとして指定されているページ・アイテムの値もサーバーに送信されるため、変更された採用日がP2_HIREDATEに割り当てられた結果が、従業員の一覧として表示されます。

ポップアップLOVはカスケードLOV親アイテムとしてP2_HIREDATEが設定されているため、クラシック・レポートと同様に変更された採用日でLOVの一覧に置き換えられます。


セッションごと(ディスク)の場合



ページ・アイテムP2_HIREDATEソースセッション・ステートの保持セッションごと(ディスク)に変更して、動作を確認します。

今までの設定を残したままだと、ほとんど動作に違いはありません。送信するページ・アイテムが設定されていると、データ・ソースを評価する際にセッション・ステートの保持がどちらであっても、画面上の値をサーバーに送信するためです。

そのため、クラシック・レポートから送信するページ・アイテムの設定を外します。遅延ロードONのまま変更しません。


また、カスケードLOVからは親アイテムの設定を外します。


採用日1960/01/01を入力し、送信します。


セッション・ステートの保持
リクエストごと(メモリーのみ)のときとは異なり、クラシック・レポート、ポップアップLOVともに、ページ・アイテムP2_HIREDATE1960/01/01を割り当てた検索結果が、従業員として一覧されます。セッション・ステートの保持セッションごと(ディスク)となっているため、ページ・アイテムP2_HIREDATE1960/01/01が設定された時点で、セッション・ステートとしてデータベースに保持されています。データ・ソースにバインド変数としてP2_HIREDATEが使われている場合、セッション・ステートに保持されているP2_HIREDATEの値が割り当てられます。


セッション・ステートに保持されているアイテムの値は、開発者ツール・バーセッションセッション・ステートの表示から参照することができます。この画面から参照できる値が、バインド変数P2_HIREDATEに割り当てられています。


この状態で、採用日を2022/08/01に変更します。採用日が2022/08/01以降の従業員は存在しません。動的アクションは有効なので、リフレッシュされたクラシック・レポートには従業員は表示されないことが期待されます。しかし、実際はそうならず、従業員の一覧は変わりません。

採用日の変更は画面上だけで、サーバー側に送信されていないためです。

変更されたページ・アイテムの値をサーバーに送信するため、リフレッシュの直前にTRUEアクションを作成します。

識別アクションとしてサーバー側のコードを実行を選択し、設定PL/SQLコードとしてnull;を記述します。送信するアイテムとしてP2_HIREDATEを指定します。コードには何も書いていないので、単にP2_HIREDATEの値をサーバーに送信するアクションです。


ページ・アイテムの値が送信されると、セッション・ステートにその値が保存されます。クラシック・レポートやポップアップLOVで、リフレッシュが行われる場合は更新されたセッション・ステートがバインド変数に割り当てられます。

コンポーネントが送信するページ・アイテムの設定を持っているのであれば、わざわざ動的アクションを作成する必要は無いでしょう。

ホーム・ページより採用日に1982/01/23を指定して、クラシック・レポートのページを開きます。

クラシック・レポートでは2名の従業員が選択されています。


ポップアップLOVもSELECT文は同等なので、従業員は2名になります。


採用日を1960/01/01に変更します。動的アクションにより、ページ・アイテムP2_HIREDATEの値1960/01/01がサーバーに送信され、クラシック・レポートがリフレッシュされます。

結果としてクラシック・レポートにはすべての従業員が一覧されます。


ポップアップLOVには変更がなく、従業員は2名です。ポップアップLOVはリフレッシュされていないためです。ポップアップLOVをリフレッシュするためには、カスケードLOV親アイテムの設定が必要です。



まとめ


  1. 画面上の値をSQLのバインド変数に割り当てるには、送信するページ・アイテムの設定を使用する。もしくは、それと同等の設定を使用する。(ポップアップLOVの場合はカスケードLOV)。
  2. 送信するページ・アイテムにてバインド変数にページ・アイテムの値を割り当てている場合、セッション・ステートに値を保持する必要性はほぼない。
  3. 送信するページ・アイテムの設定を持たないがリフレッシュが可能なコンポーネントであれば、セッション・ステートの保持セッションごと(ディスク)にし、動的アクションでページ・アイテムの値をサーバーに送信することで対応できる。
  4. 送信するページ・アイテムの設定がなく、リフレッシュにも対応していないコンポーネントを更新するには、ページの送信を実施する必要がある。

以上です。

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