Oracle® Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド 11g リリース2 (11.1.2.4.0) B69399-03 |
|
![]() 前 |
![]() 次 |
この章では、JDeveloperで提供されるOracle ADFモデル・テスターを使用して、ADFビュー・オブジェクト問合せ結果を対話的にテストする方法について説明します。この章では、Business Component APIを使用してJDeveloper外部のテスト・クライアントに含まれるビュー・オブジェクト・インスタンスにアクセスする方法についても説明します。
この章の内容は次のとおりです。
JDeveloperには、アプリケーション・ユーザー・インタフェースを使用せず、またはテスト・クライアントのプログラムを記述せずに、データ・モデルのすべての面をテストできるようにする、対話型アプリケーション・モジュール・テスト・ツールが用意されています。多くの場合、Oracle ADFモデル・テスターを実行すると、開発時にビジネス・サービスのデータ機能を最も迅速に実行できます。
注意: アプリケーション・モジュールをプログラムによってテストする場合は、テスト・クライアントを記述できます。詳細は、6.4.2項「コマンドラインJavaテスト・クライアントの作成方法」を参照してください。問合せの実行をログに出力する場合は、ADF Loggerを使用してください。詳細は、36.6項「ADF Loggerの使用」を参照してください。 |
Oracle ADFモデル・テスターを使用すると、独自のカスタム・ユーザー・インタフェースを作成する前に、エンド・ユーザーとアプリケーション・モジュールのデータ・モデルとの対話をシミュレートできます。UIページを作成した後も、Oracle ADFモデル・テスターは問題発生時の診断に役立ちます。Oracle ADFモデル・テスターで問題を再現して、問題がアプリケーションのビュー・レイヤーまたはコントローラ・レイヤーにあるのか、あるいはビジネス・サービス・レイヤーのアプリケーション・モジュール自体にあるのかを確認できます。
ビュー・インスタンスを使用する前に、他のADF機能を理解しておくと役立つ場合があります。次に、関連する他の機能へのリンクを示します。
ビュー・オブジェクト・インスタンスで構成されるデータ・モデルを作成する方法の詳細は、第9章「アプリケーション・モジュールによるビジネス・サービスの実装」を参照してください。
ADF Business Componentsのカスタム・クラスでよく記述、使用またはオーバーライドするコードについては、付録D「ADF Business Componentsのよく使用されるメソッド」を参照してください。
oracle.jbo
パッケージに関連するAPIのドキュメントについては、次のJavadocリファレンス・ドキュメントを参照してください。
Oracle Fusion Middleware Oracle ADF Model Java APIリファレンス
データ・モデル・プロジェクトで作成したビュー・オブジェクトをテストするには、テスト対象のビュー・オブジェクトのインスタンスを定義するアプリケーション・モジュールを作成する必要があります。アプリケーション・モジュールは、Oracle ADFモデル・テスター(またはUIクライアント)がアプリケーション・データの操作に使用するトランザクション・コンポーネントです。アプリケーション・モジュールで使用される一連のビュー・オブジェクトは、それ自体のデータ・モデル、つまり、クライアントがユーザー・インタフェースを介して表示および操作できる一連のデータを定義します。
アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、アプリケーション・ナビゲータからアクセスできるOracle ADFモデル・テスターを使用します。Oracle ADFモデル・テスターの使用方法の詳細は、6.3項「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
個別のビュー・オブジェクトのインスタンスを定義するアプリケーション・モジュールを作成するには、「新規ギャラリ」から使用できる「アプリケーション・モジュールの作成」ウィザードを使用します。
始める前に:
アプリケーション・モジュールの知識があると役立ちます。詳細は、6.2項「ビュー・インスタンスをテストするためのアプリケーション・モジュールの作成」
次のタスクを完了する必要があります。
個別のビュー・オブジェクト・インスタンスをテストするためのアプリケーション・モジュールを作成する手順:
アプリケーション・ナビゲータで、アプリケーション・モジュールを作成するプロジェクトを右クリックし、「新規」を選択します。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADF Business Components」、「アプリケーション・モジュール」の順に選択して、「OK」をクリックします。
「項目」リストで、「アプリケーション・モジュール」を選択し、アプリケーション・モジュールの作成ウィザードを起動します。
アプリケーション・モジュールの作成ウィザードの「名前」ページで、パッケージ名およびアプリケーション・モジュール名を指定します。「次へ」をクリックします。
「データ・モデル」ページで、以前に定義したビュー・オブジェクトのインスタンスを指定し、このビュー・オブジェクト・インスタンスの名前をクライアントで認識される名前とまったく同じ名前に編集します。次に、「終了」をクリックします。
「データ・モデル」ページに表示されるデフォルトのインスタンス名を受け入れるかわりに、インスタンス名をわかりやすい名前に変更できます(たとえば、デフォルト名OrderItems1
のかわりに、AllOrderItems
に名前を変更できます)。
アプリケーション・モジュールの作成ウィザードを使用して、ビュー・オブジェクトが表すマスター/ディテール関連に基づいてアプリケーション・モジュールのビュー・オブジェクトの階層を作成することもできます。
始める前に:
アプリケーション・モジュールの知識があると役立ちます。詳細は、6.2項「ビュー・インスタンスをテストするためのアプリケーション・モジュールの作成」
次のタスクを完了する必要があります。
ビュー・オブジェクト関連に基づいてアプリケーション・モジュールを作成する手順:
アプリケーション・ナビゲータで、アプリケーション・モジュールを作成するプロジェクトを右クリックし、「新規」を選択します。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADF Business Components」、「アプリケーション・モジュール」の順に選択して、「OK」をクリックします。
「項目」リストで、「アプリケーション・モジュール」を選択し、アプリケーション・モジュールの作成ウィザードを起動します。
アプリケーション・モジュールの作成ウィザードで、「データ・モデル」ノードを選択します。
左側の「選択可能なビュー・オブジェクト」リストで、アクティブに調整するマスターにする必要があるビュー・オブジェクトのインスタンスを選択します。
リスト内のマスター・ビュー・オブジェクトには、このビュー・オブジェクトにビュー・リンクがあることを示すプラス記号が表示されます。ビュー・リンクは、マスター/ディテール階層の定義に必要です。
たとえば、図6-1は、選択したPersonsVO
と、「新規ビュー・インスタンス」フィールドで名前を変更したAuthenticatedUser
を示しています。
選択したマスター・ビュー・オブジェクトを「データ・モデル」リストに移動します。
たとえば、図6-2は、「データ・モデル」リストに追加した後の新規作成したマスター・ビュー・インスタンスAuthenticatedUser
を示しています。
「データ・モデル」リストで、新規作成したマスター・ビュー・インスタンスを選択して強調表示しておきます。これは、追加するディテール・ビュー・インスタンスのターゲットになります。次に、「選択可能なビュー・オブジェクト」リストで、マスター・ビュー・オブジェクトの下のディテール・ビュー・オブジェクトを特定して選択します。
たとえば、図6-3は、マスター・ビュー・オブジェクトPersonsVO
の下にある、OrdersVO via PersonsToOrders
という名前のディテール・ビュー・オブジェクトOrdersVO
を示しています。この名前はビュー・リンクPersonsToOrders
を表し、PersonsVO
とOrdersVO
間のマスター/ディテール階層を定義します。ディテール・ビュー・インスタンスの名前はMyOrders
に変更されます。
追加したマスター・インスタンスにディテール・インスタンスを追加するには、「データ・モデル」リストで選択したマスター・ビュー・インスタンスの下に、ディテール・ビュー・オブジェクトを移動します。
図6-4は、データ・モデルにAuthenticatedUser
のディテールとして新規作成したディテール・ビュー・インスタンスMyOrders
を示しています。
別の階層レベルを追加するには、新しく追加したディテール・インスタンスを「データ・モデル」リストで選択してから、新しいディテール・インスタンスを移動します。このディテール・インスタンスは、前に追加したディテール・インスタンスとマスター/ディテール関係を持ちます。
データ・モデルには、ビュー・オブジェクト関係でサポートされているだけの数の階層レベルを含めることができます。たとえば、図6-5には、「データ・モデル」リストに、インスタンスAuthenticatedUser
(PersonsVO
から名前を変更)がMyOrders
(OrdersVO via PersonsToOrders
から名前を変更)のマスターとして、またこれがMyOrderItems
(OrderItemsVO via OrdersToOrderItems
から名前を変更)のマスターとして表示されています。ディテール・ビュー・オブジェクトのMyOrderItems
は、別のビュー・オブジェクトのマスターではないため、階層の最後のレベルになります。
Oracle ADFモデル・テスターを使用すると、独自のカスタム・ユーザー・インタフェースを作成する前に、エンド・ユーザーとアプリケーション・モジュールのデータ・モデルとの対話をシミュレートできます。UIページを作成した後も、Oracle ADFモデル・テスターは問題発生時の診断に役立ちます。Oracle ADFモデル・テスターで問題を再現して、問題がアプリケーションのビューまたはコントローラ・レイヤーにあるのか、あるいはビジネス・サービス・レイヤーのアプリケーション・モジュール自体にあるのかを確認できます。
アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、アプリケーション・ナビゲータからアクセスできるOracle ADFモデル・テスターを使用します。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。詳細は、6.3項「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
アプリケーション・モジュール構成でビュー・オブジェクトをテストする手順:
アプリケーション・ナビゲータで、目的のアプリケーション・モジュールおよびビュー・オブジェクトを含むプロジェクトを展開します。
アプリケーション・モジュールを右クリックし、「実行」を選択します。
または、デバッグを有効にしたOracle ADFモデル・テスターでアプリケーションを実行する場合は、「デバッグ」を選択します。JDeveloperにより、ログ・ウィンドウのデバッガ・プロセス・パネルおよび各種デバッガ・ウィンドウが開きます。たとえば、Oracle ADFモデル・テスターを使用してデバッグする場合、ステータス・メッセージと例外を表示し、ソース・コードをステップ・インおよびステップ・アウトし、ブレークポイントを管理できます。
ADF Business Componentsのデバッグに特有の診断メッセージを受信する方法の詳細は、6.3.8項「ADF Business Componentsデバッグ診断を有効化する方法」を参照してください。
「ビジネス・コンポーネント構成の選択」ダイアログで、「ビジネス・コンポーネントの構成名」リストから目的のアプリケーション・モジュール構成を選択し、Oracle ADFモデル・テスターを実行します。
デフォルトでは、アプリケーション・モジュールには、AppModuleName
Local
およびAppModuleName
Shared
という名前のデフォルトの構成のみがあります。たとえば、図6-6は、データベースに接続するアプリケーション・モジュールで使用するStoreFrontModuleLocal
構成を示しています。
アプリケーション・モジュール用として別の追加構成を作成してある場合、かわりにこれらの1つを使用してアプリケーション・モジュールをテストするには、「接続」をクリックする前に、「構成」ダイアログの「ビジネス・コンポーネントの構成名」ドロップダウン・リストから目的の構成を選択します。
「接続」をクリックし、選択した構成を使用してアプリケーション・モジュールを起動します。
Oracle ADFモデル・テスターでビュー・オブジェクトを実行するには、データ・モデル・ツリーを開き、目的のビュー・オブジェクト・ノードをダブルクリックします。
ビュー・オブジェクト・インスタンスはすでにテスト・セッションで実行されているように表示される場合があります。この場合、Oracle ADFモデル・テスターの右側のデータ・ビュー・ページには、すでにビュー・オブジェクト・インスタンスの問合せ結果が表示されています。Oracle ADFモデル・テスターでは、読取り専用ビュー・オブジェクトのデータ・ビュー・ページのフィールドは常に無効として表示されます。これは、このビュー・オブジェクトで表されるデータが編集できないためです。たとえば、図6-7では、ビュー・インスタンスProducts
のデータがテスターに表示されています。「製品ID」、「言語」、「カテゴリ」などのフィールドは、属性を編集できないため、無効として表示されます。
Oracle ADFモデル・テスターの左側にあるデータ・モデル・ツリーのノードを右クリックし、そのノードのポップアップ・メニューを表示します。たとえば、ビュー・オブジェクト・ノードでは、データ・モデル・ツリーからのビュー・オブジェクトの削除、およびその他のタスクの実行のため、必要に応じて問合せを再実行できます。
タブのポップアップ・メニューを表示するには、図6-8で示すように、開いているデータ・ビューアのタブを右クリックします。たとえば、データ・ビューアを閉じたり、別のウィンドウで開くことができます。
エンティティ・ベースのビュー・オブジェクトの対話的テストは、読取り専用ビュー・オブジェクトと同じ方法で行います。目的のビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加してから、Oracle ADFモデル・テスターを使用してこのアプリケーション・モジュールをテストします。
Oracle ADFモデル・テスターでは、アプリケーション・モジュールを簡単にテストおよびデバッグできるので、非常に便利です。表6-1に、エンティティ・ベースのビュー・オブジェクトを表示した場合にOracle ADFモデル・テスターのツールバー・ボタンで実行される操作の概要を示します。
表6-1 Oracle ADFモデル・テスターのツールバー・ボタン
ボタン | 操作 | 使用方法 |
---|---|---|
|
別の行に移動 |
Oracle ADFモデル・テスターで表示される現在の行を変更します。最初、前、次、または最後の行に移動します。 |
|
新規行を挿入 |
新規の行を作成して挿入します。 |
|
現在の行を削除 |
現在の行を削除します。 |
|
データベースへの変更を保存 |
ADF Business Componentsキャッシュに加えた変更をポストしてコミットします。 |
|
前回の保存以降の変更をすべて取消し |
ADF Business Componentsキャッシュで加えた変更を破棄して元の値に戻し、データベースにポストされたすべての変更をロールバックします。 |
|
ビュー基準の指定 |
「ビュー基準」ダイアログが表示されます。ここでビュー基準を作成して、マスター・ビュー・オブジェクト・インスタンスに適用できます。 |
|
行の検証 |
すべてのエンティティ・オブジェクト・インスタンスに対して定義済の検証規則を適用し、現在の行を検証します。最低1つのフィールドが編集可能でないと、使用できません。 |
|
バインド変数の編集 |
「バインド変数」ダイアログが表示され、ビュー・オブジェクト問合せで使用されるバインド・パラメータの値を入力できます。問合せ文のビュー・オブジェクト問合せでバインド・パラメータが使用されていないと、使用できません。 |
アプリケーション・モジュールに追加したエンティティ・ベースのビュー・オブジェクトをテストするには、アプリケーション・ナビゲータからアクセスできるOracle ADFモデル・テスターを使用します。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。詳細は、6.3項「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
アプリケーション・モジュール構成を使用してエンティティ・ベースのビュー・オブジェクトをテストする手順:
アプリケーション・ナビゲータでアプリケーション・モジュールを選択し、ポップアップ・メニューから「実行」を選択します。
Oracle ADFモデル・テスター構成の選択ダイアログで「接続」をクリックし、目的とするテスト用の構成を使用します。
Oracle ADFモデル・テスターでエンティティ・ベースのビュー・オブジェクトを実行するには、データ・モデル・ツリーを開き、目的のビュー・オブジェクト・ノードをダブルクリックします。
読取り専用ビュー・オブジェクトと異なり、データ・ビュー・ページに表示されるフィールドは、そのビュー・オブジェクトで表されるデータを編集できるため、有効として表示されます。
編集可能なフィールドでは、個々の値の更新と入力したデータの検証チェックを実行できます。
参照されるエンティティを持つビュー・インスタンスの場合は、外部キー値を変更して、参照部分の変更を確認できます。
ツールバー・ボタンを使用すると、行の移動、作成、削除、および現在の行の検証など、行レベルの操作が可能です。
エンド・ユーザーによるデータ・ビュー・ページ操作のシミュレーションの詳細は、6.3.5項「Oracle ADFモデル・テスターでのエンド・ユーザーによる対話のシミュレーション方法」を参照してください。
通常、データ・モデル・プロジェクトに対して行う変更は、Oracle ADFモデル・テスターを実行しても自動的に取得されません。ただし、表示されたデータ・モデルとデータ・モデル・プロジェクトの同期を取る必要があるときはいつでも、Oracle ADFモデル・テスターがデータ・モデル・プロジェクトからメタデータをリロードできます。このオプションを使用すると、Oracle ADFモデル・テスターを終了してプロジェクトを編集しOracle ADFモデル・テスターを再実行しなくても、最新の変更を表示できます。
「アプリケーションのリロード」オプションを使用すると、特にOracle ADFモデル・テスターとJDeveloperを繰り返し切り替えて作業する場合に時間を節約できます。たとえば、Oracle ADFモデル・テスターの実行中に、新しいビュー・インスタンスを使用してデータ・モデルを変更する必要が生じたり、ビュー・インスタンスにLOV属性定義が足りないことが判明することがあります。JDeveloperに戻り、Business Componentsの概要エディタを使用して変更操作を行い、データ・モデルのメタデータを変更します。その後、プロジェクトを再コンパイルした後(必須の手順)、Oracle ADFモデル・テスターに戻って、プロジェクトのクラス・パスから更新済のメタデータをリロードできます。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。詳細は、6.3項「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
稼働中のOracle ADFモデル・テスターにデータ・モデルのメタデータを再ロードする手順:
アプリケーション・ナビゲータで、目的アプリケーション・モジュールを右クリックして、「実行」を選択します。
データ・モデルをテストし、行う変更を決定します。Oracle ADFモデル・テスターは終了しないでください。
JDeveloperで、目的の変更を行い、データ・モデル・プロジェクトを再コンパイルします(たとえば、「アプリケーション・ナビゲータ」で、データ・モデル・プロジェクトを右クリックし、「メイク」を選択して再コンパイル手順を完了します)。
メタデータに対して行う変更とプロジェクトのコンパイルに関連性はありませんが、メタデータをクラス・パスにコピーし、Oracle ADFモデル・テスターでリロードできるようにするには、コンパイル手順を実行する必要があります。
ADFモデル・テスターに戻り、データ・モデル・ツリーの上にある「アプリケーション・メタデータのリロード」ボタンをクリックします。Oracle ADFモデル・テスターの開いているウィンドウがすべて閉じます。
また、Oracle ADFモデル・テスターの「ファイル」メニューから、「アプリケーションのリロード」を選択してもかまいません。
目的のウィンドウを再度開き、行った変更を表示します。
Oracle ADFモデル・テスターを起動すると、JDeveloperによってこのツールが別プロセスで開始され、Oracle ADFモデル・テスターが表示されます。ダイアログの左側のツリーには、アプリケーション・モジュールのデータ・モデルのすべてのビュー・オブジェクト・インスタンスが表示されます。目的のビュー・オブジェクト・インスタンスをダブルクリックすると、Oracle ADFモデル・テスターでデータ・ビュー・ページが表示され、問合せ結果をインスペクトできます。たとえば、図6-7は、展開されたツリーでビュー・インスタンスProducts
をダブルクリックし、右側のデータ・ビュー・ページにこのビュー・インスタンスのデータが表示された様子を示しています。
データは編集できないため、表示する読取り専用のビュー・オブジェクトすべてに対して、データ・ビュー・ページは無効になっています。ただし、読取り専用のビュー・オブジェクトの場合でも、ツールはいくつかの有用な機能を備えています。
「ラベル・テキスト」ヒントに基づいたUIヒント、およびフォーマット・マスクが正しく定義されているかどうかを検証できます。
ツールバー・ボタンを使用してデータのスクロールもできます。
Query-By-Example基準を入力して、検査対象のデータのある特定の行を検索できます。ツールバーの「ビュー基準の指定」ボタンをクリックすると、「ビュー基準」ダイアログに使用可能なQBE基準のリストが表示されます。
たとえば、図6-9に示すように、FindByProductNameCriteria
などのビュー基準を選択し、ProductName
属性にP%
などの問合せ基準を入力して「検索」をクリックすると、検索対象を文字P
で始まる名前の製品のみに絞り込むことができます。
6.3.2項「エンティティ・ベースのビュー・オブジェクトの対話的テスト方法」で説明しているように、行の挿入、更新および削除をシミュレートできるエンティティ・ベースのビュー・オブジェクトを作成する場合は、Oracle ADFモデル・テスターをより便利に使用できます。
Oracle ADFモデル・テスターを起動すると、アプリケーション・モジュールのデータ・モデルで定義されているビュー・オブジェクト・インスタンスの階層が左側のツリーに表示されます。データ・モデルにマスター/ディテールのビュー・インスタンス関係が定義されている場合、ツリーには親ノードと子コードとして関係が表示されます。マスター/ディテールのビュー・インスタンス間のノードは、マスターで現在の行が変更されたときにマスター/ディテールをアクティブに調整するビュー・リンク・インスタンスを示します。たとえば、図6-10では、ツリーが開かれ、マスター・ビュー・インスタンスProducts
とディテール・ビュー・インスタンスWarehouseStockLevels
のマスター/ディテール関係が示されています。選択されているノード、ProductsToWarehouseStockLevels1
は、マスター/ディテール関係が定義されているビュー・リンク・インスタンスです。
ビュー・リンク・インスタンスをダブルクリックすると、マスター・オブジェクトが実行され、データ・ビュー・ページにマスター/ディテール・データが表示されます。たとえば、図6-11では、ツリーのProductsToWarehouseStockLevels1
ビュー・リンク・インスタンスをダブルクリックすると、データ・ビュー・ページ上部のProducts
マスター・ビュー・インスタンスと、データ・ビュー・ページ下部のWarehouseStockLevels
ビュー・インスタンスが実行されます。ビュー・オブジェクト・ノード上に表示される追加ポップアップ・メニュー項目では、データ・モデル・パネルからのビュー・オブジェクトの削除、およびその他のタスクの実行のため、必要に応じて問合せを再実行できます。
マスター/ディテール・データ・ビュー・ページでは、問合せ結果をスクロールできます。また、エンティティ・ベースのビュー・オブジェクトのインスタンスは完全に編集可能なため、読取り専用ビュー・オブジェクトの読取り専用のデータを表示している無効な UIコントロールを表示するかわりに、データ・ビュー・ページには編集可能なフィールドが表示されます。作成、挿入、更新、検証、コミットおよびロールバックを自由に試すことができます。
たとえば、複数のデータ・ビュー・ページを同時に開いて、マスター/ディティール階層の複数レベルを表示できます。「連結解除」ポップアップ・メニュー項目を使用して、任意のタブを別のウィンドウで開き、複数のビュー・オブジェクトのデータを同時に視覚化します。
マスター/ディテール・データ・ビュー・ページを使用して、アプリケーションの様々な機能領域をテストできます。
Oracle ADFモデル・テスターのツールバーのナビゲーション・ボタンをクリックすると、現在のマスター・ビュー・オブジェクトの行が正しく調整されているかどうかを確認できます。たとえば、図6-11は、製品と倉庫のマスター/ディテール階層を示しています。マスター・パネルの次の行ボタンをクリックすると、(製品IDで識別された)次の製品がマスター・パネルに表示され、ディテール・パネルが更新されてこの製品を在庫として持つ倉庫と数量のリストが表示されます。
エンティティ・ベースのビュー・オブジェクトの属性は、基礎となるエンティティ・オブジェクト属性からUIヒントを継承します。データ・ビュー・ページに表示されるプロンプトを見ると、属性ごとにわかりやすいラベル・テキストUIヒントが正しく定義されているかどうかを確認できます。エンティティ・オブジェクトにヒントを設定する方法の詳細は、5.13項「ビュー・オブジェクトのUIヒントの定義」を参照してください。
定義した検証規則に応じて、無効な値を入力して検証例外のトリガーおよび検証を試行できます。たとえば、レンジ検証規則を定義した場合、レンジ外の値を入力し、次のようなエラーが表示されるのを確認します。
(oracle.jbo.AttrSetValException) Valid product codes are between 100 and 999
ツールバーで「ロールバック」ボタンをクリックし、データを以前の状態に戻してください。
アプリケーションにおいて、リソース・メッセージ・バンドル内に代替言語を定義する場合、これらの言語を認識するようにOracle ADFモデル・テスターを構成できます。Oracle ADFモデル・テスターで「ロケール」メニューを表示し、利用可能な言語の中から選択できます。
Oracle ADFモデル・テスターのデフォルト言語を指定する手順:
JDeveloperの「ツール」から、「プリファレンス」を選択します。
選択パネルで「ADFビジネス・コンポーネント」を展開し、「テスター」を選択します。
Oracle ADFモデル・テスターでエンティティ・ベースのビュー・オブジェクトを実行するには、データ・モデル・ツリーを開き、目的のビュー・オブジェクト・ノードをダブルクリックします。
Oracle ADFモデル・テスター・ページで、リソース・メッセージ・バンドルを作成したロケールを「選択済」リストに追加します。
または、特定のアプリケーション・モジュール構成に対してADFビジネス・コンポーネントのランタイム構成プロパティを設定することによっても、デフォルト言語を構成できます。これらのランタイム・プロパティにより、Oracle ADFモデル・テスターでデフォルトとして表示される言語も決定されます。構成に対する「構成の編集」ダイアログで、「プロパティ」タブを選択し、国と言語に対して目的の国コードを入力します。たとえば、イタリア語を指定するには、次の2つのプロパティに対してIT
およびit
と入力します。
jbo.default.country
= IT
jbo.default.language
= it
Oracle ADFモデル・テスターで言語メッセージ・バンドルをテストすることで、UIヒントの翻訳が正しく配置されているかどうかを検証できます。または、メッセージ・バンドルが特定の属性の日付書式を定義している場合は、ツールによって日付書式の変更(たとえば、04/12/2013
から12/04/2013
へ)を検証できます。
データをスクロールするか、Oracle ADFモデル・テスターのツールバーにある「ビュー基準の指定」ボタンを使用して検索すると、エンティティ・ベースのビュー・オブジェクトの問合せのWHERE
句を正しく変更し、外部結合を使用するようにしたかどうかを検証できます。想定どおりに行が表示されるはずです。
マスター・ビュー・オブジェクトの主キー属性の変更も試行できます。これにより、対応する参照情報が新しい主キー値を反映するように自動的に更新されているかどうかを検証できます。
ビュー・オブジェクト・レベルで定義したUIヒントによって、通常は基礎となるエンティティ・オブジェクトから継承されるUIヒントが上書きされたかどうかは、Oracle ADFモデル・テスターを使用して検証します。複数の属性が同じラベル・テキストを共有していることに気付いた場合は、ビュー・オブジェクト・レベルで目的の属性に対するUIヒントを編集できます。たとえば、「ラベル・テキスト」ヒントを、RegisteredDate
属性は「Member Since」、ProvisionedFlag
属性は「Provisioned?」に設定します。
エンティティ・ベースのビュー・オブジェクトを表示する際に、ビュー・オブジェクト・インスタンスに対してOracle ADFモデル・テスターのツールバーの行の作成ボタンをクリックすると、新しい空白の行が作成されます。宣言的なデフォルト値があるフィールドの場合、その値が空白行に表示されます。DBSequence
値の属性を使用すると、新しい行に一時値が表示されます。すべての必須フィールドに入力した後、「コミット」ボタンをクリックしてトランザクションをコミットします。コミットが成功した後、トリガーによって割り当てられた実際の主キーがフィールドに表示されます。
ビュー・オブジェクトとエンティティ・オブジェクトが実行時に連携する場合、マルチユーザー環境でアプリケーションを実行すると2つの例外が発生する可能性があります。これらの例外に備えて、Oracle ADFモデル・テスターを使用して、テスト目的のマルチ・ユーザー環境をシミュレートできます。たとえば、アプリケーションにビュー・オブジェクト問合せの編集フォームが表示される場合に、2人のユーザーがフォームで同じ属性を編集しようとすると、どのような動作が予想されるでしょうか。
予想される動作を理解するために、アプリケーション・モジュール上でOracle ADFモデル・テスターの2つのインスタンスを開き、同一のビュー・オブジェクト属性を編集する2人のユーザーをシミュレートします。2つのインスタンスを開いたまま、どのようにマルチユーザー例外が発生するかを表す次の2つのテストを実行します。
Oracle ADFモデル・テスターの1つのインスタンスで、既存のビュー・オブジェクトの属性を変更し、このフィールドから次に進みます。次に、テスターのもう1つのインスタンスで、同じビュー・オブジェクトの属性をなんらかの形で変更してみます。2人目のユーザーには、oracle.jbo.AlreadyLockedException
が発生します。
ここで、Oracle ADFモデル・テスターの「接続」ダイアログの「プロパティ」ページで、jbo.locking.mode
の値をpessimistic
に変更し、テストを繰り返して試行します(デフォルト・モードはoptimistic
に設定されています)。エラーが発生するのは、2人目のユーザーが変更をコミットした後ではなく、値を変更した直後であることがわかります。
Oracle ADFモデル・テスターの1つのインスタンスで、既存のビュー・オブジェクトの属性を変更し、このフィールドから次に進みます。次に、テスターのもう1つのインスタンスで、同じビュー・オブジェクトの属性を変更せずに取得してみます。最初のウィンドウに戻り、変更をコミットします。2人目のユーザーが同じ属性を変更しようとすると、oracle.jbo.RowInconsistentException
が発生します。これは、2人目のユーザーが行をエンティティ・キャッシュに取得した後に、行が別のユーザーによって変更されてコミットされたためです。
「ビジネス・コンポーネント構成の選択」ダイアログを使用して、事前定義済の構成を選択し、実行時構成プロパティの名前付きセットを使用してツールを実行できます。また、「構成の選択」ダイアログの「プロパティ」タブでは、選択済の構成設定を参照したり、テスターの現在の実行に対する構成設定をオーバーライドしたりできます。たとえば、「プロパティ」タブを開いて、次の2つのプロパティに目的の国コード(たとえば、イタリアを表すIT
)を設定することにより、Oracle ADFモデル・テスターの1つのインスタンスに対してUIヒントのデフォルト言語を変更できます。
jbo.default.country = IT
jbo.default.language = it
ヒント: 構成に対して永続的な変更を行う場合は、Configuration Managerを使用して、現在の構成をコピーし、目的のプロパティ・セットを設定した構成を新たに作成できます。たとえば、イタリア語のテストを行う場合はいつでも、デフォルトの |
oracle.jbo
ログ出力に診断ロギングを構成している場合、Oracle ADFモデル・テスターを起動すると、JDeveloperによりADF Business Componentsのデバッグ診断メッセージがJDeveloperの「ログ」ウィンドウにリダイレクトされます。図6-12に、ADF Business Componentsのデバッグ診断が有効になるようにFINEST
に設定されたoracle.jbo
ログ出力を示します。
oracle.jbo
ログ出力は、統合WebLogic Serverでアプリケーションを実行する前、またはアプリケーションの実行中に構成できます。ロギングは、サーバーを再起動しなくても開始されます。診断メッセージのログ出力を得るためにアプリケーションをデバッグ・モードで実行する必要はありません。
oracle.jbo
のログ出力が構成された状態で、次にOracle ADFモデル・テスターを実行してビュー・オブジェクトをダブルクリックすると、例6-1に示すように、「ログ」ウィンドウに詳細な診断出力が表示されます。oracle.jbo
ログ出力にログ・レベルFINEST
を構成すると、ADF Business Componentsフレームワークのコンポーネントによってアプリケーションに実行されるすべての内容を表示できます。
例6-1 Oracle ADFモデル・テスターの診断出力
: [355] Oracle SQLBuilder: Registered driver: oracle.jdbc.OracleDriver [356] Creating a new pool resource [357] **** DBTransactionImpl establishNewConnection [358] Successfully logged in [359] JDBCDriverVersion: 11.1.0.7.0-Production [360] DatabaseProductName: Oracle [361] DBTransactionImpl initTransaction [362] Replacing: null with: StoreServiceAM_AddressesPageDef [363] Replacing: null with: StoreServiceAM_MostPopularProductsByCategoriesPageDef ... [537] Orders ViewRowSetImpl.execute caused params to be "un"changed [538] Column count: 41 [539] ViewObject: Orders Created new QUERY statement [540] Orders>#q computed SQLStmtBufLen: 952, actual=865, storing=895 [541] SELECT OrderEO.ORDER_ID, OrderEO.ORDER_DATE, OrderEO.ORDER_SHIPPED_DATE, FROM ORDERS OrderEO ORDER BY OrderEO.ORDER_DATE desc [542] Bind params for ViewObject: Orders
下位互換性の目的で、データ・モデル・プロジェクトに対し従来のようにJavaシステム・プロパティjbo.debugoutput=console
を使用して、ADF Business Componentsデバッグ診断を有効化できます。このプロパティを設定するには、データ・モデル・プロジェクトの「プロジェクト・プロパティ」ダイアログの実行/デバッグ/プロファイルページを開きます。「編集」をクリックして選択した実行構成を編集し、ページ内の「Javaオプション」フィールドに-Djbo.debugoutput=console
を追加します。このプロパティの他の有効な値は、silent
(指定されていない場合、デフォルト)およびfile
です。fileオプションを選択すると、診断はsystem temp
ディレクトリに書き込まれます。
-Djbo.debugoutput
システム・プロパティの他の有効な値は、silent
(指定されていない場合、デフォルト)およびfile
です。file
オプションを入力すると、診断はシステムのtemp
ディレクトリに書き込まれます。
ビュー・オブジェクトとエンティティ・オブジェクトにより、すべてのエンタープライズ・アプリケーション開発者が実行する必要のある次の2つの重要なジョブが単独で簡略化されます。
SQL問合せ結果の操作
データベース表内の行の変更および検証
エンティティ・ベースのビュー・オブジェクトは、エンド・ユーザーが表示または変更できるようにする必要のあるデータを任意に選択して問い合せることができます。エンド・ユーザーによる変更が可能なデータは、再使用可能なビジネス・ドメイン・レイヤーによって検証および保存されます。開発者が指定するのは、開発者のみが把握できる重要事項です。
ビジネス・ドメイン・レイヤーにどのビジネス・ロジックを適用するかの決定
画面に表示する必要のあるデータを記述する問合せの決定
これらにより、開発者のアプリケーションが独自のものになります。実装の残りの詳細部分は、エンティティ・ベースのビュー・オブジェクトに組み込まれた機能によって処理されます。
注意: 行キーおよびエンティティ・キャッシュがトランザクションで果す役割について理解することは、エンティティ・ベースのビュー・オブジェクトの本質を明確にするために役立つ重要な概念です。これら2つの概念は、6.4.1項「ビュー・オブジェクトのデフォルト行セットを使用した操作のViewObjectインタフェース・メソッド」で説明します。 |
エンティティ・ベースのビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加した後、問合せの実行時に行われる処理を確認できます。読取り専用ビュー・オブジェクトの場合と同様、エンティティ・ベースのビュー・オブジェクトが標準のJDBC (Java Database Connectivity) APIを使用してデータベースにSQL問合せを直接送信し、データベースが結果セットを生成します。ただし、読取り専用ビュー・オブジェクトの場合とは異なり、エンティティ・ベースのビュー・オブジェクトは、データベースの結果セットの各行を取得するときに、関連付けられているエンティティ・オブジェクトの慣用名に基づいて行属性を分割します。この分割の際、各ビュー・オブジェクトのエンティティ・オブジェクトの慣用名に適切なタイプのエンティティ・オブジェクト行が作成され、問合せによって取得された関連属性がこれらのエンティティ行に移入され、このようなエンティティ行がそれぞれ個別のエンティティ・キャッシュに格納されます。これにより、データの複製コピーを格納するかわりに、ビュー行は、これを構成するエンティティ行部分を指し示すだけでになります。
図6-13は、エンティティ・キャッシュにより、2つのエンティティ・ベース・ビュー・オブジェクトの結果セット属性がどのように分割されるかを示しています。この例では、データベース結果セットで強調表示された行は、主キー112
のOrder
エンティティ行と、主キー301
のCustomerInfo
エンティティ行に分割されています。
6.4.1.2項「エンティティ・キャッシュがトランザクションで果す役割」で説明するように、findByPrimaryKey()
を使用してキャッシュに取り込んだエンティティ行には、エンティティ・オブジェクトのすべての属性が含まれています。一方、エンティティ・ベースのビュー・オブジェクトの問合せ結果の行を分割して作成されたエンティティ行には、問合せ結果に表れる属性の値のみが含まれます。これには完全な属性セットは含まれていません。このようにエンティティ行が部分的に移入されることにより、実行時のパフォーマンスが大幅に最適化されます。
一般的なエンタープライズ・アプリケーションで変更される行と比較して、取得される行の比率が非常に高くなるため、表示する必要がある属性のみをメモリーに読み込むことにより、常にすべての属性をメモリーに読み込む場合よりもメモリーを節約できます。
このような方法で問合せ結果のデータを基礎となるエンティティ行の構成要素部分に分割すると、現在のトランザクションが変更された場合、問い合せた結果のデータを含むすべての行で整合している結果が表示されるという、重要な利点が得られます。つまり、あるビュー・オブジェクトで顧客301
のPaymentType
属性を変更できる場合、顧客301
のPaymentType
属性を表示する任意のエンティティ・ベースのビュー・オブジェクトのすべての行が即座に更新され、変更が反映されます。顧客301
に関連付けられたデータがCustomerInfo
エンティティ・キャッシュで主キー301
を持つエンティティ行に格納されるのは1回のみであるため、オーダーのPaymentType
属性を問い合せたビュー行はどれも、この単一のエンティティ行を指し示すことになります。
このような実装の詳細は、ビュー・オブジェクトの行セット内の行を操作するクライアントに対しては完全に非表示にされます。クライアントは、ビュー行を操作して属性を取得して設定する際、これらの属性がその背後でどのようにエンティティ行に関連付けられているかには気付きません。
ユーザーがビュー行属性を変更しようとすると、基礎となるエンティティ行に応じてこのビュー行属性の変更を自動的に調整する一連の手順が実行されます。これらの手順により、エンティティ・マップ属性で定義された検証規則は、値が変更される前にトリガーされます。
図6-14は、ユーザーがエンティティ・マップされた属性を更新しようとするときに実行時に発生する基本的な手順を示しています。この例では、変更される属性Status
が、検証規則が定義されているエンティティ・オブジェクトの慣用名にマップされています。
ユーザーがStatus
属性の値をShip
に設定しようとします。
Status
はOrder
エンティティ・オブジェクトの慣用名にマップされた属性であるため、ビュー行は、Order
エンティティ・キャッシュ内で主キー112
を持つ、基礎となるエンティティ行に設定されている属性を委譲します。
Order
エンティティ・オブジェクトのStatus
属性に対する属性レベルの検証規則が評価され、規則が失敗した場合は変更が失敗します。
Status
属性の検証規則によってShipDate
属性がプログラム的に参照されるとします(たとえば、Order
は発注日と同日に出荷済にはできないというビジネス・ルールを適用する必要がある場合など)。ShipDate
は、問合せによって取得されたOrder
属性ではないため、Order
エンティティ・キャッシュ内に部分的に移入されたエンティティ行にはありません。
ビジネス・ルールでエンティティ・オブジェクトのすべての属性を常に参照可能にするため、エンティティ・オブジェクトはこの状況を検出し、主キーによって変更されるエンティティ行についてOrder
エンティティ・オブジェクト属性のセット全体を失敗にします(主キーはビュー・オブジェクトに適用される各エンティティ・オブジェクトの慣用名に表示されます)。
属性レベルの検証がすべて成功した後、エンティティ・オブジェクトでは、最初の属性の変更を許可する前にORDERS
表でこの行にロックをかけます。
この行をロックできた場合、行内のStatus
属性の設定が成功し、エンティティ行でこの値が変更されます。
注意:
|
ユーザーが外部キーの属性を変更しようとすると、基礎となるエンティティ行に応じてこのビュー行属性の変更を自動的に調整する一連の手順が実行されます。これらの手順により、外部キーのエンティティ・マップ属性で定義された検証規則は、値が変更される前にトリガーされます。また、変更された外部キー属性のビュー行に、すべての参照されたエンティティ・オブジェクトの正しい属性が反映されます。
図6-15は、ユーザーが外部キーのエンティティ・マップ属性を更新しようとするときに実行時に発生する基本的な手順を示しています。この例では、変更される属性CustomerInfoId
は、エンティティ・オブジェクトの慣用名Order
にマップされており、ここでこの属性は別のエンティティ・オブジェクトであるCustomerInfo
と関連付けられます。
ユーザーがCustomerInfoId
属性の値を300
に設定しようとします。
CustomerInfoId
はOrder
エンティティ・オブジェクトの慣用名にマップされた属性であるため、ビュー行は、Order
エンティティ・キャッシュ内で主キー112
を持つ、基礎となるエンティティ行に設定されている属性を委譲します。
Order
エンティティ・オブジェクトのCustomerInfoId
属性に対する属性レベルの検証規則が評価され、規則が失敗した場合は変更が失敗します。
この行はすでにロックされているため、行内のCustomerInfoId
属性の設定が成功し、エンティティ行でこの値が変更されます。
Order
エンティティ・オブジェクトの慣用名のCustomerInfoId
属性は、CustomerInfo
エンティティ・オブジェクトに関連付けられているため、外部キー値をこのように変更すると、ビュー行で、顧客301
の現在のエンティティ行部分が、新しいCustomerInfoId = 300
に対応するエンティティ行に置き換えられます。これにより、オーダー112
のビュー行が300
のエンティティ行を指し示すよう効率的に変更できるため、ビュー行のPaymentType
の値が更新され、この新しく割り当てられた顧客の参照情報が正しく反映されます。
変更に問題がなく、トランザクションをコミットするとします。図6-16に示すとおり、次の2つの基本手順があります。
Transaction
オブジェクトにより、保留中の変更リスト内の無効なエンティティ行が検証されます。
保留中の変更リスト内のエンティティ行がデータベースに保存されます。
この図は、1つの変更済エンティティ・オブジェクトの検証処理が他のエンティティ・オブジェクトに対する変更にプログラム的に影響する前に行う、手順1のループを示します。保留中の変更リスト上で無効なエンティティのリストが処理された後、リストにまだエンティティが残されている場合、トランザクションで別のパスが実行されます。リストのパススルーは最大10回行われます。この時点でまだ無効なエンティティ行がある場合は通常、ビジネス・ロジックにエラーがあり、このビジネス・ロジックを調査する必要があるため、例外がスローされます。
ビュー・オブジェクトの問合せを再実行する場合、デフォルトでは、最新の結果セットを読み込むための準備中、現在の行セット内のビュー行は無視されます。ただし、このビュー・オブジェクト操作はエンティティ・キャッシュには直接影響しません。この場合、ビュー・オブジェクトがデータベースに対してSQLを送信することによってプロセスが再開され、データベースの結果セット行が取得され、エンティティ行部分に分割されます。
注意: 通常、ビュー・オブジェクトでデータの問合せを再実行する場合、この操作では最新のデータベース情報を取得します。かわりにビュー・オブジェクトの問合せ対象をキャッシュ内の既存のエンティティ行のみ、またはすでにビュー・オブジェクトの行セット内にある既存の行に制限して、データベースのラウンドトリップを回避する場合は、42.5項「行セットのメモリー内でのソート処理とフィルタ処理の実行」を参照してください。 |
問合せの再実行時におけるこのエンティティ行分割プロセスの一環として、エンティティ行の属性が変更されていない場合、エンティティ・キャッシュ内の値が更新され、新しい問合せ結果の値が反映されます。
一方、現在のトランザクションでエンティティ行属性の値が変更されている場合、問合せ再実行時のエンティティ行の分割プロセスでは、値はリフレッシュされません。現在のトランザクションでコミットされない変更はそのまま残されるため、エンド・ユーザーの論理作業ユニットは保持されます。任意のエンティティ属性値の場合と同様、これらの保留中の変更は、変更済エンティティ行を参照する任意のエンティティ・ベースのビュー・オブジェクト行に継続して表示されます。
注意: エンド・ユーザーによる行の挿入および削除はエンティティ・キャッシュでも管理されるため、問合せの再実行時に、新規行を表示して削除済の行をスキップできます。新しい行の動作の詳細は、42.1.2項「同じエンティティに基づくビュー・オブジェクトでの新しい行の一貫性の保持」を参照してください。 |
たとえば、図6-17は、ユーザーがOrders
ビュー・オブジェクト・インスタンスを使用する別のページにドリルダウンし、オーダー112
に関する詳細を取得するシナリオを示しており、これは現在のトランザクションの保留中の変更のコンテキストで発生します。このビュー・オブジェクトには、プライマリOrders
の慣用名と、CustomerInfo
の参照の慣用名の、2つのエンティティ・オブジェクトの慣用名があります。問合せ結果がエンティティ行に分割されると、前のOrderInfo
ビュー行で変更されたものと同じOrder
エンティティ行を指し示すことになります。つまり、エンド・ユーザーには保留中の変更が正しく表示され、オーダーはこのトランザクションのsking
に割り当てられています。
2つの異なるビュー・オブジェクトが、参照情報の2つの異なるサブセットを取得でき、属性の一致するセットの有無にかかわらず、結果がマージされます。たとえば、図6-17もこの状況を示しており、Orders
ビュー・オブジェクトはユーザーのEmail
を問い合せていますが、OrderInfo
ビュー・オブジェクトはユーザーのPaymentOption
を問い合せています。この図は、実行時に行われる処理を示しており、取得した行を分割する際に、すでにキャッシュ内にある部分的に移入されたエンティティ行とは異なる属性セットがエンティティ行部分に含まれる場合、属性はマージされます。その結果、キャッシュ内の部分的に移入されたエンティティ行に、オーバーラップするユーザー属性のサブセットが統合されます。一方、キャッシュ内になかったjchen
(ユーザー302)の場合、新しいエンティティ行にはEmail
属性のみが含まれ、PaymentOption
は含まれません。
ビュー・オブジェクトには、SQLの実行方法とデータベースからデータをフェッチする方法を制御するチューニング・パラメータが用意されています。これらのチューニング・パラメータは、ビュー・オブジェクトの実行時パフォーマンスで重要な役割を果たします。アプリケーションでフェッチ・オプションが正常にチューニングされないと、ビュー・オブジェクトが必要以上の量のデータをフェッチし、データベースへのラウンドトリップの回数が非常に増える場合があります。
表6-2に示すように、概要エディタの「一般」ページの「チューニング」セクションでは、フェッチ・オプションを設定できます。
表6-2 ビュー・オブジェクトのパフォーマンスをチューニングするためのパラメータ
フェッチをチューニングするパラメータ | 使用方法 |
---|---|
フェッチ・モード |
デフォルトのフェッチ・オプションは「すべての行」オプションで、「必要に応じて」( |
フェッチ・サイズ |
「次の単位で」フィールドでは、「フェッチ・モード」オプションと連携して、データベースから一度にフェッチされるレコード数(ビュー・オブジェクトXMLの |
最大フェッチ・サイズ |
ビュー・オブジェクトのデフォルトの最大フェッチ・サイズは-1で、ビュー・オブジェクトでフェッチできる行数に制限がないことを示します。結果セットにn行のデータしか含まれない場合は、「行番号までのみ」のオプションを選択して、nに設定してください。開発者は、
前述のように、最大フェッチ・サイズを0に設定すると、ビュー・オブジェクトは挿入専用になります。この場合は、選択問合せは発行されないため、行はフェッチされません。 アプリケーションのすべてのビュー・オブジェクト問合せに対してグローバルなしきい値を指定する必要がある場合は、 |
転送専用モード |
データセットのトラバースで転送しか実行されない場合は、転送専用モードを使用すると、データセットを反復する場合のパフォーマンスが向上します。転送専用モードは、ビュー・オブジェクトで |
ビュー・オブジェクトをチューニングする場合は、次の点も考慮する必要があります。
大規模なデータ・セット: ビュー・オブジェクトは、ユーザーが結果の特定のページにジャンプできるように、大規模なデータ・セット内でページ移動するメカニズムを備えています。この機能は、ビュー・オブジェクトでsetRangeSize(
n
)
、setAccessMode(RowSet.RANGE_PAGING)
の順にコールすることによって設定します(nは、1ページに含める行数)。ユーザーがデータ・セット内の特定のページに移動する場合、アプリケーションはビュー・オブジェクトでscrollToRangePage(P)
をコールするとページPに移動できます。範囲ページングでは、現在のページの行のみがフェッチされて、ビュー・オブジェクトの行キャッシュに入れられるため、1ページのデータを取得するたびに問合せ実行のコストがかかります。範囲ページングは、すべての行をフェッチしてビュー・オブジェクトの行キャッシュに入れるほうが有利な場合には適していません(たとえば、データ・セットのすべての行を読み取ってLOVを生成したり、小さいデータ・セットのレコードを前後にページ移動したりする必要がある場合です)。
スピルオーバー: JVMコンテナでメモリーが不足した場合に、データ・ソースを仮想メモリーとして使用する機能が用意されています。デフォルトでは、この機能は無効になっていますが、メモリーが不足した場合の最後の手段として、jbo.use.pers.coll=true
に設定することにより有効にできます。スピルオーバーを有効にすると、パフォーマンスが大きく影響を受ける場合があります。
SQLプラットフォーム: SQL92準拠の汎用データベースへの接続に汎用SQL92 SQLプラットフォームを使用すると、ビュー・オブジェクトの一部のチューニング・オプションが正常に機能しなくなります。汎用SQL92 SQLプラットフォームを選択することにより最も影響を受けるパラメータは、フェッチ・サイズです。SQL92 SQLプラットフォームを使用すると、ビュー・オブジェクトの構成に関係なく、フェッチ・サイズがデフォルトで10行に設定されます。SQLプラットフォームは、データベース接続を定義するときに設定したり、adf-config.xml
ファイル内にグローバルなプロジェクト設定として定義できます。デフォルトでは、SQLプラットフォームはOracle
になります。SQLプラットフォームを手動で上書きする場合は、起動時にパラメータ-Djbo.SQLBuilder="SQL92"
をJVMに渡すこともできます。
また、データベースのパフォーマンスを向上するために、ビュー・オブジェクトの関連するSQLをチューニングするための次のオプションも用意されています。
バインド変数: ビュー・オブジェクトに関連付けられた問合せに、実行ごとに変更される可能性がある値が含まれる場合は、バインド変数を使用します。問合せでバインド変数を使用すると、データベースで問合せを再解析する必要なく、問合せを再実行できます。バインド変数は、ビュー・オブジェクトの概要エディタの「問合せ」ページでビュー・オブジェクトに追加できます。詳細は、5.10項「バインド変数の使用」を参照してください。
問合せオプティマイザ・ヒント: ビュー・オブジェクトでは、ヒントをデータベースに渡して、関連する問合せに使用される実行計画に影響を与えることができます。オプティマイザ・ヒントは、ビュー・オブジェクトの概要エディタの「チューニング」セクションの「データベースから取得」グループ・ボックスで指定できます。オプティマイザ・ヒントの詳細は、42.2.4.3項「必要に応じた問合せオプティマイザ・ヒントの指定」を参照してください。
少なくとも1つのビュー・オブジェクト・インスタンスを含む、操作中のアプリケーション・モジュールをテストする準備ができたら、単純なテスト・クライアント・プログラムを構築して、含まれるビュー・オブジェクト・インスタンスにあるデータを使用したプログラムによる操作の基礎を示すことができます。
アプリケーション・モジュールのデータ・モデルにアクセスするクライアントの視点からは、読取り専用ビュー・オブジェクトを操作するAPIと、エンティティ・ベースのビュー・オブジェクトを操作するAPIは同一のものです。機能的な主な相違点は、エンティティ・ベースのビュー・オブジェクトでは、ビュー・オブジェクトのデータを完全に更新できる点です。エンティティ・ベースのビュー・オブジェクトを含むアプリケーション・モジュールは、作業ユニットを定義し、トランザクションを管理します。この項では、Fusion Order DemoのStoreFrontAM
アプリケーション・モジュールを操作する簡単な4つのテスト・クライアント・プログラムを使用して、次について説明します。
マスター/ディテール/ディテール階層の反復
行の検索および外部キー値の更新
新規注文の作成
行を識別する行キーの取得
oracle.jbo
パッケージのViewObject
インタフェースには、データ取得タスクを簡単に実行するメソッドが用意されています。例に使用されるこれらのメソッドの一部には、次のものが含まれます。
executeQuery()
: ビュー・オブジェクトの問合せを実行し、その結果の行セットを移入します。
setWhereClause()
: 実行時に動的条件を追加して検索を絞り込みます。
setNamedWhereClauseParam()
: 名前付きバインド変数の値を設定します。
hasNext()
: 行セット・イテレータが結果の最終行に到達したかどうかをテストします。
next()
: 行セット・イテレータを行セット内の次の行へ進めます。
getEstimatedRowCount()
: ビュー・オブジェクトの問合せが戻す行の数をカウントします。
ビュー・オブジェクトを操作する場合は、通常、単一の結果行セットのみを1回で操作します。このきわめて一般的なユースケースを単純化するために、図6-18に示すように、ビュー・オブジェクトにはデフォルトのRowSet
が含まれ、ここにデフォルトのRowSetIterator
が含まれています。デフォルトのRowSetIterator
により、デフォルト行セットに自動的に適用されることを認識しながら、ViewObject
コンポーネント自体でデータ取得メソッドのすべてを直接コールできるようになります。
注意: 第42章「ビュー・オブジェクトの高度な手法」では、単一のビュー・オブジェクトを使用して複数の異なる結果行セットを生成する状況が示されています。また、1つの行セットに対して複数の異なる行セット・イテレータを作成するシナリオも説明されています。ただし、多くの場合は単一のイテレータのみ必要です。 |
このガイドで「ビュー・オブジェクトの行を使用して操作中」という表現を使用した場合は、正確にはビュー・オブジェクトのデフォルト行セットの行を使用して操作するということを意味しています。同様に、「ビュー・オブジェクトの行全体で反復処理する」という表現は、正確にはビュー・オブジェクトのデフォルト行セットのデフォルト行セット・イテレータを使用して、その行をループするという意味です。
ビュー行を操作するときは、oracle.jbo
パッケージの中のRow
インタフェースを使用します。図6-19に示すように、このインタフェースには、任意の行を識別するKey
オブジェクトへのアクセスに使用できる、getKey()
と呼ばれるメソッドが含まれています。Row
インタフェースは、oracle.jbo.server
パッケージ内の Entity
インタフェースによって拡張されます。この関係は、エンティティ行という用語が適切であることの具体的な理由になります。エンティティ行がビジネス・ロジックのカプセル化やデータベース・アクセスの処理のための追加機能をサポートしている場合でも、エンティティ行はRow
としてそのまま扱うことができます。
エンティティ・ベースのビュー・オブジェクトは、キーによる行の検索タスクを、基礎となるエンティティ行部分に委譲します。
前述のとおり、ビュー行とエンティティ行はどちらも単一属性または複数属性のキーをサポートしているため、特定のRow
に関連付けられたKey
オブジェクトにより、キーを構成するすべての属性がカプセル化されます。Key
オブジェクトがある場合は、任意の行セットに対してfindByKey()
メソッドを使用して、Key
オブジェクトに基づいて行を検索できます。findByKey()
メソッドを使用してキーによってビュー行を検索すると、ビュー行ではエンティティ定義のfindByPrimaryKey()
メソッドを使用して、ビュー行キーに属性を提供する各エンティティ行が検索されます。
読取り専用ビュー・オブジェクトの場合、このタスクを委譲する基礎となるエンティティ行がないため、主キー属性が1つでも検出されると、ビュー・オブジェクトの実装により、manageRowsByKey
フラグが自動的に有効になります。このため、読取り専用ビュー・オブジェクトの場合は、findByKey()
メソッドが成功します。manageRowsByKey
フラグが有効でない場合、キーを使用して現在の行を設定するなどのUI操作は、findByKey()
メソッドに依存するため機能しません。
注意: エンティティ・ベースのビュー・オブジェクトを定義する場合、デフォルトでは、すべてのエンティティ・オブジェクトの慣用名の主キー属性は、「キー属性」プロパティの設定が |
アプリケーション・モジュールは、論理的な作業ユニットのトランザクション・コンテナです。実行時には、指定された名前の構成情報を使用してデータベース接続を確立し、トランザクション管理を付属のTransaction
オブジェクトに委譲します。論理作業ユニットには、様々なタイプの複数のエンティティ行の検索や変更が含まれる場合があるため、Transaction
オブジェクトには、現在のユーザーのトランザクションに関連するエンティティ行を保持するための作業領域として、エンティティ・キャッシュが用意されています。各エンティティ・キャッシュには単一のエンティティ・タイプの行が含まれるため、2つ以上のエンティティ・オブジェクトが関連するトランザクションでは、これらのエンティティ行の作業用コピーが個別キャッシュに保持されます。
エンティティ・オブジェクトの関連エンティティ定義を使用して、アプリケーション・モジュールで既存のエンティティ行を検索し、変更するためのコードを記述できます。図6-20に示すとおり、Order
エンティティ・オブジェクトのエンティティ定義に対してfindByPrimaryKey()
をコールすると、そのキーを持つ行を取得できます。この行がまだエンティティ・キャッシュ内にない場合、エンティティ・オブジェクトによってこの行をデータベースから取得するための問合せが実行されます。この問合せにより、基礎となる表からエンティティ・オブジェクトのすべての持続属性が選択され、エンティティ・オブジェクトの主キー属性に対応する列に適したWHERE
句を使用して行が検索されます。同一トランザクション中に同じエンティティ行をキーによって引き続き検索する場合、この行をキャッシュ内で検索することにより、データベースへのトリップを回避します。特定のエンティティ・キャッシュでは、主キーによってエンティティ行が索引付けされます。これにより、キャッシュ内でのエンティティ行の検索処理が速くなります。
アソシエーション・アクセッサ・メソッドを使用して関連エンティティ行にアクセスする場合、これらの行はエンティティ・キャッシュからも取得されます。関連エンティティ行がキャッシュ内にない場合は、データベースから取得されます。最後に、エンティティ・キャッシュは、新しいエンティティ行が保存されるまで保持される場所でもあります。つまり、createInstance2()
メソッドを使用してエンティティ定義に対して新しいエンティティ行を作成する場合、このエンティティ行はエンティティ・キャッシュに追加されます。
エンティティ行を作成、変更または削除すると、このエンティティ行はトランザクションの保留中の変更リストに自動的に登録されます。Transaction
オブジェクトに対してcommit()
をコールすると、保留中の変更リストが処理され、まだ無効の新規または変更済エンティティ行があるかどうかが検証されます。保留リスト内のエンティティ行がすべて有効である場合、Transaction
により、データベースのSAVEPOINT
が発行され、データベースへのエンティティ行の保存が調整されます。すべて正常に完了すると、最終的にデータベースのCOMMIT
文が発行されます。問題が発生した場合、Transaction
によってROLLBACK TO SAVEPOINT
が実行され、ユーザーはエラーを修正するか、または再試行できるようになります。
アプリケーション・モジュールで使用されるTransaction
オブジェクトは、単一のエンド・ユーザー・トランザクション用のエンティティ行の作業セットです。設計上、これは共有のグローバル・キャッシュではありません。データベース・エンジン自体は、複数の同時ユーザーを対象とした非常に効率的な共有グローバル・キャッシュです。ADF Business Componentsでは、すべての作業で行われてきたデータベースの共有グローバル・キャッシュ機能の微調整を繰り返すのではなく、その結果が意識的に採用されています。refresh()
メソッドをコールすると、データベースから単一のエンティティ・オブジェクトのデータをいつでもリフレッシュできます。Transaction
オブジェクトに対してsetClearCacheOnCommit()
またはsetClearCacheOnRollback()
を使用すると、コミットまたはロールバック時にエンティティ・キャッシュを消去するかどうかを制御できます。デフォルトはそれぞれfalse
とtrue
です。また、Transaction
オブジェクトにはclearEntityCache()
メソッドも用意されており、このメソッドを使用して、特定のエンティティ・タイプ(またはすべてのタイプ)のエンティティ行をプログラムで消去できます。エンティティ・キャッシュを消去すると、そのタイプのエンティティ行は、主キーによって次に検出されるか、エンティティ・ベースのビュー・オブジェクトによって取得されるときに、データベースから取得できます。
テスト・クライアント・プログラムを作成するには、「新規ギャラリ」からアクセス可能なJavaクラスの作成ウィザードを使用します。
テスト・クライアント・プログラムを作成するときに「Javaクラスの作成」ウィザードを使用すると、プログラム・ファイルがソース・エディタで開き、事前定義済のコード・テンプレートからコードを追加してテスト・クライアントを作成することができます。
スケルトンJavaテスト・クライアントを作成する手順:
アプリケーション・ナビゲータで、テスト・クライアントを作成するプロジェクトを右クリックし、「新規」を選択します。
「新規ギャラリ」で、「一般」を展開し、「Java」、「Javaクラス」の順に選択して、「OK」をクリックします。
「Javaクラスの作成」ダイアログで、TestClient
などのクラス名、oracle.fodemo.storefront.client
などのパッケージ名を入力し、「拡張」フィールドがjava.lang.Object
となっていることを確認します。
「オプション属性」で、「スーパークラスからのコンストラクタ」の選択を解除し、「mainメソッド」を選択します。
「OK」をクリックします。
.java
はソース・エディタで開き、例6-2で示すように、スケルトン・コードが示されます。
テスト・クライアントのスケルトン・コードを作成したら、JDeveloperで利用可能な事前定義済のbc4jclient
コードを使用してファイルの編集を開始できます。
bc4jclientコード・テンプレートを挿入する手順:
main()
メソッドの本体にある空白行にカーソルを置き、bc4jclient
コード・テンプレートを使用して必要なコードを数行作成します。
bc4jclient
という文字を入力し、[Ctrl]キーを押しながら[Enter]キーを押します。
JDeveloperによって、例6-3に示すように、テンプレートを使用してクラス・ファイルが展開されます。
amDef
およびconfig
変数の値を調整して、アプリケーション・モジュール定義の名前と使用する構成の名前をそれぞれ反映します。
例6-3では、変更した行は次のようになります。
String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM"; String config = "StoreServiceAMLocal";
最後に、コール内のビュー・オブジェクト・インスタンス名を、作業するfindViewObject()
に変更します。アプリケーション・モジュールの概要エディタの「データ・モデル」ページで「データ・モデル」ツリーに表示される名前を正確に指定します。
例6-3では、変更した行は次のようになります。
ViewObject vo = am.findViewObject("Persons");
例6-3 TestClient.javaの拡張されたスケルトン・コード
package oracle.fodemo.storefront.client; import oracle.jbo.client.Configuration; import oracle.jbo.*; import oracle.jbo.domain.Number; import oracle.jbo.domain.*; public class TestClient { public static void main(String[] args) { String amDef = "test.TestModule"; String config = "TestModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); ViewObject vo = am.findViewObject("TestView"); // Work with your appmodule and view object here Configuration.releaseRootApplicationModule(am,true); } }
アプリケーション・モジュールに対するスケルトン・テスト・クライアントには、例6-4に示すようなソース・コードが含まれている必要があります。
注意: 9.10項「アプリケーション・モジュールのクライアント・インタフェースのプログラム的操作」における例では、このテスト・クライアント・サンプルコードが拡張され、カスタム・アプリケーション・モジュール・サービス・メソッドのコールも説明されます。 |
例6-4 アプリケーション・モジュール・テスト・クライアント・プログラムの作業中スケルトン・コード
package oracle.fodemo.storefront.client; import oracle.jbo.ApplicationModule; import oracle.jbo.Row; import oracle.jbo.RowSet; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; public class TestClient { public static void main(String[] args) { String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM"; String config = "StoreServiceAMLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); // 1. Find the Persons view object instance. ViewObject personList = am.findViewObject("Persons"); // Work with your appmodule and view object here Configuration.releaseRootApplicationModule(am,true); } }
// Work with your appmodule and view object here
を、テスト対象のビュー・オブジェクトを実行するコードに置き換えます。たとえば、ビュー・オブジェクトの問合せを実行して戻される行数を表示し、結果をループしてデータをフェッチしコンソールに出力するには、例6-5に示すコードを、使用しているデータ・モデル・プロジェクトのコンポーネントに合うように変更します。
例6-5 マスター/ディテール・ビュー・オブジェクトのループおよびコンソールへの結果の出力
// 2. Execute the query personList.executeQuery(); // 3. Iterate over the resulting rows while (personList.hasNext()) { Row person = personList.next(); // 4. Print the person's email System.out.println("Person: " + person.getAttribute("Email")); // 5. Get related rowset of Orders using view link accessor attribute RowSet orders = (RowSet)person.getAttribute("Orders"); // 6. Iterate over the Orders rows while (orders.hasNext()) { Row order = orders.next(); // 7. Print out some order attribute values System.out.println(" ["+order.getAttribute("OrderStatusCode")+"] "+ order.getAttribute("OrderId")+": "+ order.getAttribute("OrderTotal")); if(!order.getAttribute("OrderStatusCode").equals("COMPLETE")) { // 8. Get related rowset of OrderItems RowSet items = (RowSet)order.getAttribute("OrderItems"); // 9. Iterate over the OrderItems rows while (items.hasNext()) { Row item = items.next(); // 10. Print out some order items attributes System.out.println(" "+item.getAttribute("LineItemId")+": "+ item.getAttribute("LineItemTotal")); } } } }
最初の行では、executeQuery()
メソッドをコールして、ビュー・オブジェクト問合せを実行します。これにより、ビュー・オブジェクトのhasNext()
メソッドがfalse
を戻すまで反復処理を行うwhile
文を使用してループできる、ゼロまたは1行以上の行セットを生成します。ループ内では、コードで現行のRow
をperson
という名前の変数に入れてから、この現行のRow
オブジェクト上でgetAttribute()
メソッドを2回呼び出し、Email
属性とOrders
属性の値を取得して、オーダー情報をコンソールに出力します。2番目のwhile
文では、オーダーの明細項目に対して同じタスクを実行します。
Configuration
オブジェクトでのcreateRootApplicationModule()
へのコールによって、使用するアプリケーション・モジュールのインスタンスが戻されます。デバッグ診断出力で示されるとおり、ADF Business Components実行時クラスによって、必要に応じてXMLコンポーネント定義をロードして、設計時にデータ・モデルで定義されたアプリケーション・モジュールとビュー・オブジェクト・コンポーネントのインスタンスをインスタンス化します。アプリケーション・モジュール上のfindViewObject()
メソッドによって、アプリケーション・モジュールのデータ・モデルからビュー・オブジェクト・インスタンスを名前で検索します。例6-5で示されているループの後、テスト・クライアントはConfiguration
オブジェクトでreleaseRootApplicationModule()
を実行します。これにより、アプリケーション・モジュールを使用して処理したことが通知され、アプリケーション・モジュールに使用されたデータベース接続のように、フレームワークでリソースをクリーン・アップできるようになります。
createRootApplicationModule()
およびreleaseRootApplicationModule()
メソッドは、アプリケーション・モジュール・コンポーネントへのコマンドライン・アクセスの場合に非常に便利です。ただし、通常、ADFベースのWebまたはSwingアプリケーションのコンテキストでは、これら2行のコードを記述する必要はありません。このような場合は、ADFモデル・データ・バインディング・レイヤーとADFビジネス・サービス・レイヤーの自動的な連携により、ADFアプリケーション・モジュール・コンポーネントが取得およびリリースされます。
getEstimatedRowCount()
メソッドは、含まれている行数を判断するために、RowSet
で使用されます。
long numReqs = reqs.getEstimatedRowCount();
getEstimatedRowCount()
の実装によって最初にSELECT COUNT(*)
の問合せが発行され、問合せから戻される行の数を計算します。問合せは、次のような文のビュー・オブジェクトの問合せ全体をラップすることにより、計算式で表されます。
SELECT COUNT(*) FROM ( ... your view object's SQL query here ... )
SELECT COUNT(*)
問合せを使用すると、必ずしもすべての行自体を取得しなくても、ビュー・オブジェクトの行数にアクセスできるようになります。このアプローチにより、大量の行数を戻す問合せを操作する場合や、問合せの結果を操作する前に問合せから戻さうる行数をテストする場合に、重要な最適化を図ることができます。
推定行数が計算されると、後続のメソッドへのコールではCOUNT(*)
問合せは再実行されません。この値は、次にこのビュー・オブジェクトの問合せが実行されるまでキャッシュされます(データベースから戻される新しい問合せ結果セットに、前回の問合せ実行時より多い、少ない、または異なる行が含まれる可能性があるためです)。推定行数は、現行トランザクションで保留中の変更、関連する新規行の数の追加、および戻された数から削除された行数の差引を考慮して自動的に調整されます。
getEstimatedRowCount()
をオーバーライドして、アプリケーションの必要性に合せて、カスタムのカウント問合せを実行することもできます。
5.6.6.2項「ビュー・リンク・アクセッサを使用したディテール・コレクションへのプログラムによるアクセス」で説明しているように、ビュー・リンク・アクセッサを使用してディテール行のRowSet
を取得すると、ビュー・オブジェクトの結果行セットで使用されるパターンと同じパターンを使用して、その行セットに含まれる行全体をループできます(例6-6を参照)。
例6-6 ディテール・コレクションへのアクセスに使用されるパターン
while (reqs.hasNext()) { Row curReq = reqs.next(); System.out.println("--> (" + curReq.getAttribute("OrderId") + ") " + curReq.getAttribute("OrderTotal")); }
例6-7は、PersonList
ビュー・オブジェクト・インスタンスを制限してperson_type_code
の値がCUST
であるユーザーのみを表示するために、動的なWHERE
句を設定するmain()
メソッドを示しています。さらに、executeAndShowResults()
メソッドは、ビュー・リンク・アクセッサ属性にアクセスし、それぞれに対してリクエスト番号(PersonId
)およびEmail
属性を出力します。
ビュー・リンク・アクセッサを使用してディテール・コレクションにアクセスするには、次の基本的な手順に従います(例6-7を参照)。
マスター・ビュー・オブジェクト・インスタンスを検索します。
問合せを実行します。
マスター・ビュー・オブジェクトの行を反復処理します。
ビュー・リンク・アクセッサ属性を使用して、関連するディテール・ビュー・オブジェクトの行セットを取得します。
ディテール・ビュー・オブジェクトの行を反復処理します。
必要に応じて、ディテール行セット属性を操作します。
パフォーマンスに関するヒント: 行をループするために記述するコードで行を表示する必要がない場合は、終了した行セットで |
例6-7 ビュー・リンク・アクセッサを使用したディテール行へのプログラムによるアクセス
package devguide.examples.readonlyvo.client; import oracle.jbo.ApplicationModule; import oracle.jbo.Row; import oracle.jbo.RowSet; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; public class TestClient2 { public static void main(String[] args) { String amDef = "devguide.examples.readonlyvo.PersonService"; String config = "PersonServiceLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); // 1. Find the Persons view object instance. ViewObject vo = am.findViewObject("PersonList"); // Add an extra where clause with a new named bind variable vo.setWhereClause("person_type_code = :ThePersonType"); vo.defineNamedWhereClauseParam("ThePersonType", null, null); vo.setNamedWhereClauseParam("ThePersonType", "CUST"); // Show results when :ThePersonType = 'CUST' executeAndShowResults(vo); Configuration.releaseRootApplicationModule(am, true); } private static void executeAndShowResults(ViewObject vo) { System.out.println("---"); // 2. Execute the query vo.executeQuery(); // 3. Iterate over the resulting rows of the Persons view object while (vo.hasNext()) { Row curPerson = vo.next(); // 4. Access the row set of Orders using the view link accessor attribute RowSet orders =(RowSet)curPerson.getAttribute("OrdersShippedToPurchaser"); long numOrders = orders.getEstimatedRowCount(); System.out.println(curPerson.getAttribute("PersonId") + " " + curPerson.getAttribute("Email")+" ["+ numOrders+" orders]"); // 5. Iterate over the resulting detail rows while (orders.hasNext()) { Row curOrder = orders.next(); // 6. Print out some Order attribute values System.out.println("--> (" + curOrder.getAttribute("OrderId") + ") " + curOrder.getAttribute("OrderTotal")); } } } }
TestClient2.java
を実行すると、例6-8に示すような出力が「ログ」ウィンドウに出力されます。各顧客がリストされ、オーダーした顧客ごとに、オーダーの合計が顧客の名前の下に表示されます。
例6-8 TestClient.javaの実行結果
--- 121 AFRIPP [0 orders] 115 AKHOO [0 orders] 109 DFAVIET [0 orders] 114 DRAPHEAL [0 orders] 118 GHIMURO [0 orders] 126 IMIKKILI [0 orders] 111 ISCIARRA [0 orders] 110 JCHEN [0 orders] 127 JLANDRY [0 orders] 112 JMURMAN [0 orders] 125 JNAYER [0 orders] 119 KCOLMENA [0 orders] 124 KMOURGOS [0 orders] 129 LBISSOT [0 orders] 113 LPOPP [1 orders] --> (1013) 89.99 120 MWEISS [1 orders] --> (1003) 5000 108 NGREENBE [1 orders] --> (1002) 1249.91 122 PKAUFLIN [0 orders] 116 SBAIDA [0 orders] 128 SMARKLE [0 orders] 117 STOBIAS [0 orders] 123 SVOLLMAN [0 orders]
デバッグ診断を有効にしてTestClient2.java
を実行すると、ビュー・オブジェクトによって実行されたSQL問合せが表示されます。ビュー・リンクのWHERE
句条件は、PersonList
ビュー・オブジェクトで現在行のディテール・サービス・リクエストのフィルタリングを自動実行するために使用されます。
別のネスト・レベルが含まれるマスター/ディテールの反復処理を行うには、次の基本的な手順に従います(例6-9を参照)。
マスター・ビュー・オブジェクト・インスタンスを検索します。
問合せを実行します。
結果の行を反復処理します。
必要に応じて、マスター行セット属性を操作します。
ビュー・リンク・アクセッサ属性を使用して、関連するディテール・ビュー・オブジェクトの行セットを取得します。
ディテール行セットの行を反復処理します。
必要に応じて、ディテール行セット属性を操作します。
ビュー・リンク・アクセッサ属性を使用して、関連する2番目のディテール・ビュー・オブジェクトの行セットを取得します。
2番目のディテール・行セットの行を反復処理します。
必要に応じて、2番目のディテール行セット属性を操作します。
例6-9では、もう1つ別のネスト・レベルを使用せずに、6.4.6項「ビュー・リンク・アクセッサを使用したディテール・コレクションのアクセス方法」で説明した、マスター/ディテール読取り専用ビュー・オブジェクトを反復するTestClient
プログラムと同じAPIを使用しています。
既存のTestClient.java
クラスでJDeveloperの「リファクタ」→「複製」機能を使用する場合、それを簡単にクローニングしてTestClient2.java
クラスを作成できます。たとえば、例6-8のTestClient.java
クラスは、この手法に適しています。
例6-9 マスター/ディテール/ディテール階層の反復
package oracle.fodemo.storefront.client; import oracle.jbo.ApplicationModule; import oracle.jbo.Row; import oracle.jbo.RowSet; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; public class TestClient2 { public static void main(String[] args) { String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM"; String config = "StoreServiceAMLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); // 1. Find the Persons view object instance. ViewObject personList = am.findViewObject("Persons"); // 2. Execute the query personList.executeQuery(); // 3. Iterate over the resulting rows while (personList.hasNext()) { Row person = personList.next(); // 4. Print the person's email System.out.println("Person: " + person.getAttribute("Email")); // 5. Get related rowset of Orders using view link accessor attribute RowSet orders = (RowSet)person.getAttribute("Orders"); // 6. Iterate over the Orders rows while (orders.hasNext()) { Row order = orders.next(); // 7. Print out some order attribute values System.out.println(" ["+order.getAttribute("OrderStatusCode")+"] "+ order.getAttribute("OrderId")+": "+ order.getAttribute("OrderTotal")); if(!order.getAttribute("OrderStatusCode").equals("COMPLETE")) { // 8. Get related rowset of OrderItems using view link accessor attribute RowSet items = (RowSet)order.getAttribute("OrderItems"); // 9. Iterate over the OrderItems rows while (items.hasNext()) { Row item = items.next(); // 10. Print out some order items attributes System.out.println(" "+item.getAttribute("LineItemId")+": "+ item.getAttribute("LineItemTotal")); } } } } Configuration.releaseRootApplicationModule(am,true); } }
このプログラムを実行すると、例6-10に示す出力が生成されます。
例6-10 TestClient2.javaの実行結果
Staff Member: David Austin [Open] 104: Spin cycle not draining 1: Researching issue Staff Member: Bruce Ernst [Closed] 101: Agitator does not work [Pending] 102: Washing Machine does not turn on 1: Called customer to make sure washer was plugged in... 2: We should modify the setup instructions to include... [Open] 108: Freezer full of frost 1: Researching issue Staff Member: Alexander Hunold [Closed] 100: I have noticed that every time I do a... [Closed] 105: Air in dryer not hot :
行を検索して外部キーの値を更新するには、次の基本的な手順に従います(例6-11を参照)。
ビュー・オブジェクト・インスタンスを検索します。
Key
オブジェクトを作成し、ビュー・インスタンスの行を参照します。
findByKey()
を使用して行を検索します。
必要に応じて、行の属性を操作します。
例6-11は、外部キーの値を検索して更新し、Orders
ビュー・オブジェクト・インスタンスの行を検索するmain()
メソッドを示しています。このサンプルでは、行の値が変更される前に、既存のOrderStatusCode
属性の値が出力されます。
例6-11 外部キー値の検索および更新
package oracle.fodemo.storefront.client; import oracle.jbo.ApplicationModule; import oracle.jbo.JboException; import oracle.jbo.Key; import oracle.jbo.Row; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; public class TestFindAndUpdate { public static void main(String[] args) { String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM"; String config = "StoreServiceAMLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); // 1. Find the Orders view object instance ViewObject vo = am.findViewObject("Orders"); // 2. Construct a new Key to find Order # 1011 Key orderKey = new Key(new Object[]{1011}); // 3. Find the row matching this key Row[] ordersFound = vo.findByKey(orderKey,1); if (ordersFound != null && ordersFound.length > 0) { Row order = ordersFound[0]; // 4. Print some order information String orderStatus = (String)order.getAttribute("OrderStatusCode"); System.out.println("Current status is: "+ orderStatus); try { // 5. Try setting the status to an illegal value order.setAttribute("OrderStatusCode","REOPENED"); } catch (JboException ex) { System.out.println("ERROR: "+ex.getMessage()); } // 6. Set the status to a legal value order.setAttribute("OrderStatusCode","PENDING"); // 7. Show the value of the status was updated successfully System.out.println("Current status is: " + order.getAttribute("OrderStatusCode")); // 8. Show the current value of the customer for this order System.out.println("Customer: " + order.getAttribute("CustomerId")); // 9. Reassign the order to customer # 113 order.setAttribute("CustomerId",113); // Luis Popp // 10. Show the value of the reference information now System.out.println("Customer: "+order.getAttribute("CustomerId")); // 11. Rollback the transaction am.getTransaction().rollback(); System.out.println("Transaction canceled"); } Configuration.releaseRootApplicationModule(am,true); } }
この例を実行すると、例6-12に示す出力が生成されます。
新しいビュー行インスタンスを作成するには、次の基本的な手順に従います(例6-13を参照)。
ビュー・オブジェクト・インスタンスを検索します。
新しい行を作成し、行セットに挿入します。
新しい行の必須属性の値を設定します。
トランザクションをコミットします。
例6-13は、Orders
ビュー・オブジェクト・インスタンスを検索し、新しい行を行セットに挿入するmain()
メソッドを示しています。Orders
ビュー・オブジェクトはエンティティ・ベースなので、CreatedBy
属性は、マップされたエンティティ・オブジェクト属性から値を導出します。このサンプルでは、トランザクションのコミット前に、残りの属性の値が設定されます。
例6-13 新規オーダーの作成
package oracle.fodemo.storefront.client; import oracle.jbo.ApplicationModule; import oracle.jbo.Row; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; import oracle.jbo.domain.DBSequence; import oracle.jbo.domain.Date; import oracle.jbo.domain.Timestamp; public class TestCreateOrder { public static void main(String[] args) throws Throwable { String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM"; String config = "StoreServiceAMLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); // 1. Find the Orders view object instance. ViewObject orders = am.findViewObject("Orders"); // 2. Create a new row and insert it into the row set Row newOrder = orders.createRow(); orders.insertRow(newOrder); // Show the entity object-related defaulting for CreatedBy attribute System.out.println("CreatedBy defaults to: " + newOrder.getAttribute("CreatedBy")); // 3. Set values for some of the required attributes Date now = new Date(new Timestamp(System.currentTimeMillis())); newOrder.setAttribute("OrderDate", now); newOrder.setAttribute("OrderStatusCode", "PENDING"); newOrder.setAttribute("OrderTotal", 500); newOrder.setAttribute("CustomerId", 110); newOrder.setAttribute("ShipToAddressId", 2); newOrder.setAttribute("ShippingOptionId", 2); newOrder.setAttribute("FreeShippingFlag", "N"); newOrder.setAttribute("GiftwrapFlag", "N"); // 4. Commit the transaction am.getTransaction().commit(); // 5. Retrieve and display the trigger-assigned order id DBSequence id = (DBSequence)newOrder.getAttribute("OrderId"); System.out.println("Thanks, reference number is " + id.getSequenceNumber()); Configuration.releaseRootApplicationModule(am, true); } }
この例を実行すると、例6-14に示す結果が生成されます。
行キーを取得して行を特定するには、次の基本的な手順に従います(例6-15を参照)。
ビュー・オブジェクト・インスタンスを検索します。
指定された値を使用してキーを作成します。
このキーを使用して行を検索します。
必要に応じて、行のキーを操作します。
例6-15は、Orders
ビュー・オブジェクト・インスタンスを検索し、行キーを作成してオーダー番号を検索するmain()
メソッドを示しています。findByKey()
メソッドでは、指定されたキーによりOrders
行を検索します。このサンプルでは、次に行のキーが表示され、OrderItems
ビュー・リンク・アクセッサを使用して行セットにアクセスし、行を反復処理して各OrderItems
行のキーが表示されます。
例6-15 行を識別する行キーの取得
package oracle.fodemo.storefront.client; import oracle.jbo.ApplicationModule; import oracle.jbo.Key; import oracle.jbo.Row; import oracle.jbo.RowSet; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; public class TestFindAndShowKeys { public static void main(String[] args) { String amDef = "oracle.fodemo.storefront.store.service.StoreServiceAM"; String config = "StoreServiceAMLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); // 1. Find the Orders view object instance ViewObject vo = am.findViewObject("Orders"); // 2. Construct a key to find order number 1011 Key orderKey = new Key(new Object[] { 1011 }); // 3. Find the Orders row with the key Row[] ordersFound = vo.findByKey(orderKey, 1); if (ordersFound != null && ordersFound.length > 0) { Row order = ordersFound[0]; // 4. Displays the key of the Orders row showKeyFor(order); // 5. Accesses row set of Orders using OrderItems view link accessor RowSet items = (RowSet)order.getAttribute("OrderItems"); // 6. Iterates over the OrderItems row while (items.hasNext()) { Row itemRow = items.next(); // 4. Displays the key of each OrderItems row showKeyFor(itemRow); } } Configuration.releaseRootApplicationModule(am, true); } private static void showKeyFor(Row r) { // get the key for the row passed in Key k = r.getKey(); // format the key as "(val1,val2)" String keyAttrs = formatKeyAttributeNamesAndValues(k); // get the serialized string format of the key, too String keyStringFmt = r.getKey().toStringFormat(false); System.out.println("Key " + keyAttrs + " has string format " + keyStringFmt); } // Build up "(val1,val2)" string for key attributes private static String formatKeyAttributeNamesAndValues(Key k) { StringBuffer sb = new StringBuffer("("); int attrsInKey = k.getAttributeCount(); for (int i = 0; i < attrsInKey; i++) { if (i > 0) sb.append(","); sb.append(k.getAttributeValues()[i]); } sb.append(")"); return sb.toString(); } }
この例を実行すると、例6-16に示す結果が生成されます。シリアライズされたキーの文字列フォーマットは16進数で、キー内のすべての属性を示す単一文字列に情報が含まれています。
アプリケーションに対してADFセキュリティを有効にし、テスト・ユーザーにjazn-data.xml
ファイルをプロビジョニングしている場合は、テスト・クライアントを実行する前に、ユーザーを認証するためのメソッド・コールを組み込む必要があります。テスト・クライアントでユーザーを認証するには、次の基本的な手順に従います(例6-17を参照)。
認証サービスを作成します。
jazn-data.xml
ファイルに定義されている、テスト・ユーザー用のログイン資格証明を渡します。
認証が成功したら、アプリケーション・モジュールをテストします。
ユーザーをログアウトします。
ADFセキュリティの構成ウィザードを実行してADFセキュリティを有効にする方法、およびJDeveloperのアイデンティティ・ストアにテスト・ユーザーを作成する方法の詳細は、35.2項「ADFセキュリティ・プロセスの概要」を参照してください。
例6-17 テスト・クライアントでのログイン資格証明の渡し方
package oracle.demo.model.test; import oracle.jbo.ApplicationModule; import oracle.jbo.Key; import oracle.jbo.Row; import oracle.jbo.RowSet; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; import oracle.adf.share.security.AuthenticationService; import oracle.adf.share.security.authentication.AuthenticationServiceUtil; import oracle.adf.share.ADFContext; import oracle.adf.share.security.SecurityContext; import oracle.adf.share.security.SecurityEnv; import javax.security.auth.Subject; public class TestAuthenticationClient { public static void main(String[] args) { String amDef = "test.TestAuthModule"; String config = "TestAuthModuleLocal"; // 1. Create authentication service. AuthenticationService authService = AuthenticationServiceUtil.getAuthenticationService(); try { // 2. Pass in user id and password defined in local identity store. authService.login("tester1", "welcome1"); } catch (Exception e) { } // Uncomment to output authentication status // String userName = ADFContext.getCurrent().getSecurityContext().getUserName(); // System.out.println("*** userName : " + userName); // Subject subject = ADFContext.getCurrent().getSecurityContext().getSubject(); // System.out.println("Subject : " + subject); // 3. Test application module if authentication succeeds. if (ADFContext.getCurrent().getSecurityContext().isAuthenticated()) { ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); ViewObject vo = am.findViewObject("TestView"); // Work with your appmodule and view object here Configuration.releaseRootApplicationModule(am,true); // 4. Log out test user. authService.logout(); // Uncomment to report logout success // boolean isAuthenticated = ADFContext.getCurrent().getSecurityContext().isAuthenticated(); // System.out.println("*** isAuthenticated : " + isAuthenticated); } } }