Oracle® Fusion Middleware Oracle Application Development FrameworkによるFusion Webアプリケーションの開発 12c (12.2.1.3.0) E90376-03 |
|
前 |
次 |
この章の内容は次のとおりです。
Oracle ADFモデル・テスターを使用してデータ・モデルの対話型ADFアプリケーション・モジュール・テストを実行します。
JDeveloperには、アプリケーション・ユーザー・インタフェースを使用せず、またはテスト・クライアントのプログラムを記述せずに、データ・モデルのすべての面をテストできるようにする、対話型アプリケーション・モジュール・テスト・ツールが用意されています。多くの場合、Oracle ADFモデル・テスターを実行すると、開発時にビジネス・サービスのデータ機能を最も迅速に実行できます。
注意:
アプリケーション・モジュールをプログラムによってテストする場合は、テスト・クライアントを記述できます。「コマンドラインJavaテスト・クライアントの作成方法」を参照してください。
Oracle ADFモデル・テスターを使用すると、独自のカスタム・ユーザー・インタフェースを作成する前に、エンド・ユーザーとアプリケーション・モジュールのデータ・モデルとの対話をシミュレートできます。UIページを作成した後も、Oracle ADFモデル・テスターは問題発生時の診断に役立ちます。Oracle ADFモデル・テスターで問題を再現して、問題がアプリケーションのビュー・レイヤーまたはコントローラ・レイヤーにあるのか、あるいはビジネス・サービス・レイヤーのアプリケーション・モジュール自体にあるのかを確認できます。
ビュー・インスタンスで作業を開始する前に、その他のOracle ADF機能を理解しておくと役に立つ場合があります。次に、関連する他の機能へのリンクを示します。
Oracle ADFモデル・テスターを実行する場合のデバッグ・ツールの使用方法の詳細は、「テストとデバッグのためのOracle ADFモデル・テスターの使用」を参照してください。
ビュー・オブジェクト・インスタンスで構成されるデータ・モデルを作成する方法の詳細は、「アプリケーション・モジュールによるビジネス・サービスの実装」を参照してください。
ADFビジネス・コンポーネントのカスタム・クラスでよく記述、使用またはオーバーライドするコードのクイック・リファレンスは、「ADFビジネス・コンポーネントのよく使用されるメソッド」を参照してください。
oracle.jbo
パッケージに関連するAPIのドキュメントについては、次のJavadocリファレンス・ドキュメントを参照してください。
Oracle ADFモデルJava APIリファレンス
ADFアプリケーション・モジュールを定義し、ビュー・オブジェクト・インスタンスを使用してデータ・モデルを構築します。必要に応じて、Oracle ADFモデル・テスターを使用してアプリケーション・モジュールをテストします。
データ・モデル・プロジェクトで作成したビュー・オブジェクトをテストするには、テスト対象のビュー・オブジェクトのインスタンスを定義するアプリケーション・モジュールを作成する必要があります。アプリケーション・モジュールは、Oracle ADFモデル・テスター(またはUIクライアント)がアプリケーション・データの操作に使用するトランザクション・コンポーネントです。アプリケーション・モジュールで使用される一連のビュー・オブジェクトは、それ自体のデータ・モデル、つまり、クライアントがユーザー・インタフェースを介して表示および操作できる一連のデータを定義します。
アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、「アプリケーション」ウィンドウからアクセスできるOracle ADFモデル・テスターを使用します。Oracle ADFモデル・テスターの使用方法の詳細は、「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
個別のビュー・オブジェクトのインスタンスを定義するアプリケーション・モジュールを作成するには、「新規ギャラリ」から使用できる「アプリケーション・モジュールの作成」ウィザードを使用します。
始める前に:
アプリケーション・モジュールの知識があると役立ちます。詳細は、「ビュー・インスタンスをテストするためのアプリケーション・モジュールの作成」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
次のタスクを完了する必要があります。
個別のビュー・オブジェクト・インスタンスをテストするためのアプリケーション・モジュールを作成するには:
「アプリケーション・モジュールの作成」ウィザードを使用して、ビュー・オブジェクトが表すマスター/ディテール関係に基づいてアプリケーション・モジュールのビュー・オブジェクトの階層を作成することもできます。
始める前に:
アプリケーション・モジュールの知識があると役立ちます。詳細は、「ビュー・インスタンスをテストするためのアプリケーション・モジュールの作成」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
次のタスクを完了する必要があります。
ビュー・オブジェクト関連に基づいてアプリケーション・モジュールを作成するには:
Oracle ADFモデル・テスターを使用し、カスタム・ユーザー・インタフェースを構築する前にシミュレート済のエンド・ユーザーとの対話を使用してADFアプリケーション・モジュールをテストして診断します。
Oracle ADFモデル・テスターを使用すると、独自のカスタム・ユーザー・インタフェースを作成する前に、エンド・ユーザーとアプリケーション・モジュールのデータ・モデルとの対話をシミュレートできます。UIページを作成した後も、Oracle ADFモデル・テスターは問題発生時の診断に役立ちます。Oracle ADFモデル・テスターで問題を再現して、問題がアプリケーションのビューまたはコントローラ・レイヤーにあるのか、あるいはビジネス・サービス・レイヤーのアプリケーション・モジュール自体にあるのかを確認できます。
アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、「アプリケーション」ウィンドウからアクセスできるOracle ADFモデル・テスターを使用します。「アプリケーション」ウィンドウからテスターを実行すると、デフォルトのアプリケーション・モジュール構成を使用してデータベースへの接続が行われます。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。詳細は、「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
テスターを実行する場合のデバッグ・ツールの使用方法を理解しておくと役に立つ場合があります。詳細は、「テストとデバッグのためのOracle ADFモデル・テスターの使用」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
アプリケーション・モジュール構成を使用してビュー・オブジェクトをテストするには:
アプリケーション・モジュールに追加したビュー・オブジェクトをテストするには、Oracle ADFモデル・テスターを使用し、特定の構成でテスターを実行します。選択する構成によって、テスターで使用されるデータベース接続が決まります。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。詳細は、「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
テスターを実行する場合のデバッグ・ツールの使用方法を理解しておくと役に立つ場合があります。詳細は、「テストとデバッグのためのOracle ADFモデル・テスターの使用」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
特定のアプリケーション・モジュール構成を使用してビュー・オブジェクトをテストするには:
アプリケーションにおいて、リソース・メッセージ・バンドル内に代替言語を定義する場合、これらの言語を認識するようにOracle ADFモデル・テスターを構成できます。Oracle ADFモデル・テスターで「ロケール」メニューを表示し、利用可能な言語の中から選択できます。
Oracle ADFモデル・テスターのデフォルト言語を指定するには:
または、特定のアプリケーション・モジュール構成に対してADFビジネス・コンポーネントのランタイム構成プロパティを設定することによっても、デフォルト言語を構成できます。これらのランタイム・プロパティにより、Oracle ADFモデル・テスターでデフォルトとして表示される言語も決定されます。ランタイム構成のプロパティを設定するには、「アプリケーション」ウィンドウでアプリケーション・モジュールをダブルクリックして、概要エディタの「構成」ナビゲーション・タブを選択します。次に、概要エディタの「構成」ページで構成を選択し、構成のハイパーリンクをクリックします。アプリケーション・モジュール構成の概要エディタ(bc4j.xcfg
ファイル)で「プロパティ」タブを選択し、「プロパティの追加」をクリックして「プロパティの追加」ダイアログから次のプロパティを選択し、「OK」をクリックします。
jbo.default.country
jbo.default.language
次に、「プロパティ」リストで、国および言語の国コードを入力します。たとえば、イタリア語を指定するには、次の2つのプロパティに対してIT
およびit
と入力します。
jbo.default.country
= IT
jbo.default.language
= it
Oracle ADFモデル・テスターで言語メッセージ・バンドルをテストすることで、UIヒントの翻訳が正しく配置されているかどうかを検証できます。または、メッセージ・バンドルが特定の属性の日付書式を定義している場合は、ツールによって日付書式の変更(たとえば、04/12/2013
から12/04/2013
へ)を検証できます。
エンティティ・ベースのビュー・オブジェクトの対話的テストは、読取り専用ビュー・オブジェクトと同じ方法で行います。目的のビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加してから、Oracle ADFモデル・テスターを使用してこのアプリケーション・モジュールをテストします。
Oracle ADFモデル・テスターでは、アプリケーション・モジュールを簡単にテストおよびデバッグできるので、非常に便利です。表8-1に、エンティティ・ベースのビュー・オブジェクトを表示した場合にOracle ADFモデル・テスターのツールバー・ボタンで実行される操作の概要を示します。
表8-1 Oracle ADFモデル・テスターのツールバー・ボタン
ボタン | 操作 | 用途 |
---|---|---|
別の行に移動 |
Oracle ADFモデル・テスターで表示される現在の行を変更します。最初、前、次、または最後の行に移動します。 |
|
新規行を挿入 |
新規の行を作成して挿入します。 |
|
現在の行を削除 |
現在の行を削除します。 |
|
データベースへの変更を保存 |
ADFビジネス・コンポーネント・キャッシュに加えた変更をポストしてコミットします。 |
|
前回の保存以降の変更をすべて取消し |
ADFビジネス・コンポーネント・キャッシュで加えた変更を破棄して元の値に戻し、データベースにポストされたすべての変更をロールバックします。 |
|
ビュー基準の指定 |
「ビュー基準」ダイアログが表示されます。ここでビュー基準を作成して、マスター・ビュー・オブジェクト・インスタンスに適用できます。 |
|
行の検証 |
すべてのエンティティ・オブジェクト・インスタンスに対して定義済の検証規則を適用し、現在の行を検証します。最低1つのフィールドが編集可能でないと、使用できません。 |
|
バインド変数の編集 |
「バインド変数」ダイアログが表示され、ビュー・オブジェクト問合せで使用されるバインド・パラメータの値を入力できます。問合せ文のビュー・オブジェクト問合せでバインド・パラメータが使用されていないと、使用できません。 |
アプリケーション・モジュールに追加したエンティティ・ベースのビュー・オブジェクトをテストするには、「アプリケーション」ウィンドウからアクセスできるOracle ADFモデル・テスターを使用します。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。「ビュー・インスタンスのテストの追加機能」を参照してください。
アプリケーション・モジュール構成を使用してエンティティ・ベースのビュー・オブジェクトをテストするには:
通常、データ・モデル・プロジェクトに対して行う変更は、Oracle ADFモデル・テスターを実行しても自動的に取得されません。ただし、表示されたデータ・モデルとデータ・モデル・プロジェクトの同期を取る必要があるときはいつでも、Oracle ADFモデル・テスターがデータ・モデル・プロジェクトからメタデータをリロードできます。このオプションを使用すると、Oracle ADFモデル・テスターを終了してプロジェクトを編集しOracle ADFモデル・テスターを再実行しなくても、最新の変更を表示できます。
「アプリケーションのリロード」オプションを使用すると、特にOracle ADFモデル・テスターとJDeveloperを繰り返し切り替えて作業する場合に時間を節約できます。たとえば、Oracle ADFモデル・テスターの実行中に、新しいビュー・インスタンスを使用してデータ・モデルを変更する必要が生じたり、ビュー・インスタンスにLOV属性定義が足りないことが判明することがあります。JDeveloperに戻り、ビジネス・コンポーネントの概要エディタを使用して変更操作を行い、データ・モデルのメタデータを変更します。その後、プロジェクトを再コンパイルした後(必須の手順)、Oracle ADFモデル・テスターに戻って、プロジェクトのクラス・パスから更新済のメタデータをリロードできます。
始める前に:
Oracle ADFモデル・テスターの知識があると役立ちます。詳細は、「Oracle ADFモデル・テスターを使用したビュー・オブジェクト・インスタンスのテスト」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
稼働中のOracle ADFモデル・テスターにデータ・モデルのメタデータを再ロードするには:
Oracle ADFモデル・テスターを起動すると、JDeveloperによってこのツールが別プロセスで開始され、Oracle ADFモデル・テスターが表示されます。ダイアログの左側のツリーには、アプリケーション・モジュールのデータ・モデルのすべてのビュー・オブジェクト・インスタンスが表示されます。目的のビュー・オブジェクト・インスタンスをダブルクリックすると、Oracle ADFモデル・テスターでデータ・ビュー・ページが表示され、問合せ結果をインスペクトできます。たとえば、図8-9は、展開されたツリーでビュー・インスタンスProducts
をダブルクリックし、右側のデータ・ビュー・ページにこのビュー・インスタンスのデータが表示された様子を示しています。
データは編集できないため、表示する読取り専用のビュー・オブジェクトすべてに対して、データ・ビュー・ページは無効になっています。ただし、読取り専用のビュー・オブジェクトの場合でも、ツールはいくつかの有用な機能を備えています。
「ラベル・テキスト」ヒントに基づいたUIヒント、およびフォーマット・マスクが正しく定義されているかどうかを検証できます。
ツールバー・ボタンを使用してデータのスクロールもできます。
Query-By-Example基準を入力して、検査対象のデータのある特定の行を検索できます。ツールバーの「ビュー基準の指定」ボタンをクリックすると、「ビュー基準」ダイアログに使用可能なQuery-by-Example基準のリストが表示されます。
たとえば、図8-9に示すように、FindByProductNameCriteria
などのビュー基準を選択し、ProductName
属性にP%
などの問合せ基準を入力して「検索」をクリックすると、検索対象を文字P
で始まる名前の製品のみに絞り込むことができます。
「エンティティ・ベースのビュー・オブジェクトの対話的テスト方法」で説明しているように、行の挿入、更新および削除をシミュレートできるエンティティ・ベースのビュー・オブジェクトを作成する場合は、Oracle ADFモデル・テスターをより便利に使用できます。
Oracle ADFモデル・テスターを起動すると、アプリケーション・モジュールのデータ・モデルで定義されているビュー・オブジェクト・インスタンスの階層が左側のツリーに表示されます。データ・モデルにマスター/ディテールのビュー・インスタンス関係が定義されている場合、ツリーには親ノードと子コードとして関係が表示されます。マスター/ディテールのビュー・インスタンス間のノードは、マスターで現在の行が変更されたときにマスター/ディテールをアクティブに調整するビュー・リンク・インスタンスを示します。たとえば、図8-10では、ツリーが開かれ、マスター・ビュー・インスタンスProducts
とディテール・ビュー・インスタンスWarehouseStockLevels
のマスター/ディテール関係が示されています。選択されているノード、ProductsToWarehouseStockLevels1
は、マスター/ディテール関係が定義されているビュー・リンク・インスタンスです。
図8-10 Oracle ADFモデル・テスターのアプリケーション・モジュールのデータ・モデル
ビュー・リンク・インスタンスをダブルクリックすると、マスター・オブジェクトが実行され、データ・ビュー・ページにマスター/ディテール・データが表示されます。たとえば、図8-11では、ツリーのProductsToWarehouseStockLevels1
ビュー・リンク・インスタンスをダブルクリックすると、データ・ビュー・ページ上部のProducts
マスター・ビュー・インスタンスと、データ・ビュー・ページ下部のWarehouseStockLevels
ビュー・インスタンスが実行されます。ビュー・オブジェクト・ノード上に表示される追加ポップアップ・メニュー項目では、データ・モデル・パネルからのビュー・オブジェクトの削除、およびその他のタスクの実行のため、必要に応じて問合せを再実行できます。
マスター/ディテール・データ・ビュー・ページでは、問合せ結果をスクロールできます。また、エンティティ・ベースのビュー・オブジェクトのインスタンスは完全に編集可能なため、読取り専用ビュー・オブジェクトの読取り専用のデータを表示している無効な UIコントロールを表示するかわりに、データ・ビュー・ページには編集可能なフィールドが表示されます。作成、挿入、更新、検証、コミットおよびロールバックを自由に試すことができます。
図8-11 Oracle ADFモデル・テスターのマスター/ディテール・データ・ビュー・ページ
たとえば、複数のデータ・ビュー・ページを同時に開いて、マスター/ディティール階層の複数レベルを表示できます。「連結解除」ポップアップ・メニュー項目を使用して、任意のタブを別のウィンドウで開き、複数のビュー・オブジェクトのデータを同時に視覚化します。
マスター/ディテール・データ・ビュー・ページを使用して、アプリケーションの様々な機能領域をテストできます。
Oracle ADFモデル・テスターのツールバーのナビゲーション・ボタンをクリックすると、現在のマスター・ビュー・オブジェクトの行が正しく調整されているかどうかを確認できます。たとえば、図8-11は、製品と倉庫のマスター/ディテール階層を示しています。マスター・パネルの次の行ボタンをクリックすると、(製品IDで識別された)次の製品がマスター・パネルに表示され、ディテール・パネルが更新されてこの製品を在庫として持つ倉庫と数量のリストが表示されます。
エンティティ・ベースのビュー・オブジェクトの属性は、基礎となるエンティティ・オブジェクト属性からUIヒントを継承します。データ・ビュー・ページに表示されるプロンプトを見ると、属性ごとにわかりやすいラベル・テキストUIヒントが正しく定義されているかどうかを確認できます。エンティティ・オブジェクトにヒントを設定する方法の詳細は、「ビュー・オブジェクトのUIヒントの定義」を参照してください。
定義した検証規則に応じて、無効な値を入力して検証例外のトリガーおよび検証を試行できます。たとえば、レンジ検証規則を定義した場合、レンジ外の値を入力し、次のようなエラーが表示されるのを確認します。
(oracle.jbo.AttrSetValException) Valid product codes are between 100 and 999
ツールバーで「ロールバック」ボタンをクリックし、データを以前の状態に戻してください。
データをスクロールするか、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人目のユーザーが行をエンティティ・キャッシュに取得した後に、行が別のユーザーによって変更されてコミットされたためです。
アプリケーション・モジュールの概要エディタを使用して、事前定義済の構成を選択し、実行時構成プロパティの名前付きセットを使用してツールを実行できます。概要エディタの「構成」ページでは、アプリケーション・モジュール構成(bc4j.xcfg
ファイルで定義)の概要エディタを開き、テスターを実行する前に構成のプロパティを指定することもできます。
アプリケーション・モジュール構成の概要エディタを表示するには、「アプリケーション」ウィンドウでアプリケーション・モジュールをダブルクリックして、概要エディタの「構成」ナビゲーション・タブを選択します。次に、概要エディタの「構成」ページで構成を選択し、構成のハイパーリンクをクリックします。アプリケーション・モジュール構成の概要エディタで「プロパティ」タブを選択し、「プロパティの追加」をクリックして「プロパティの追加」ダイアログで目的のプロパティを選択し、「OK」をクリックします。
たとえば、構成を編集し「プロパティ」タブを選択して、次の2つのプロパティを追加して目的の国コード(この場合はイタリアを表すIT
)を設定することにより、UIヒントのデフォルト言語を変更できます。
jbo.default.country = IT
jbo.default.language = it
oracle.jbo
ログ出力に診断ロギングを構成している場合、Oracle ADFモデル・テスターを起動すると、JDeveloperによりADFビジネス・コンポーネントのデバッグ診断メッセージがJDeveloperの「ログ」ウィンドウにリダイレクトされます。図8-12に、ADFビジネス・コンポーネントのデバッグ診断が有効になるようにFINEST
に設定されたoracle.jbo
ログ出力を示します。
図8-12 ADFビジネス・コンポーネントのデバッグ用のログ出力の構成
oracle.jbo
ログ出力は、統合WebLogic Serverでアプリケーションを実行する前、またはアプリケーションの実行中に構成できます。ロギングは、サーバーを再起動しなくても開始されます。診断メッセージのログ出力を得るためにアプリケーションをデバッグ・モードで実行する必要はありません。
oracle.jbo
のログ出力が構成された状態で、次にOracle ADFモデル・テスターを実行してビュー・オブジェクトをダブルクリックすると、次の例に示すように、「ログ」ウィンドウに詳細な診断出力が表示されます。oracle.jbo
ログ出力にログ・レベルFINEST
を構成すると、ADFビジネス・コンポーネント・フレームワークのコンポーネントによってアプリケーションに実行されるすべての内容を表示できます。
: [355] Oracle SQLBuilder: Registered driver: oracle.jdbc.OracleDriver [356] Creating a new pool resource [357] **** DBTransactionImpl establishNewConnection [358] Successfully logged in [359] JDBCDriverVersion: xx.xx.x.x-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ビジネス・コンポーネント・デバッグ診断を有効化できます。このプロパティを設定するには、データ・モデル・プロジェクトの「プロジェクト・プロパティ」ダイアログの実行/デバッグ/プロファイル・ページを開きます。「編集」をクリックして選択した実行構成を編集し、ページ内の「Javaオプション」フィールドに-Djbo.debugoutput=console
を追加します。このプロパティの他の有効な値は、silent
(指定されていない場合、デフォルト)およびfile
です。fileオプションを選択すると、診断はsystem temp
ディレクトリに書き込まれます。
-Djbo.debugoutput
システム・プロパティの他の有効な値は、silent
(指定されていない場合、デフォルト)およびfile
です。file
オプションを入力すると、診断はシステムのtemp
ディレクトリに書き込まれます。
ビュー・オブジェクトとエンティティ・オブジェクトにより、すべてのエンタープライズ・アプリケーション開発者が実行する必要のある次の2つの重要なジョブが単独で簡略化されます。
SQL問合せ結果の操作
データベース表内の行の変更および検証
エンティティ・ベースのビュー・オブジェクトは、エンド・ユーザーが表示または変更できるようにする必要のあるデータを任意に選択して問い合せることができます。エンド・ユーザーによる変更が可能なデータは、再使用可能なビジネス・ドメイン・レイヤーによって検証および保存されます。開発者が指定するのは、開発者のみが把握できる重要事項です。
ビジネス・ドメイン・レイヤーにどのビジネス・ロジックを適用するかの決定
画面に表示する必要のあるデータを記述する問合せの決定
これらにより、開発者のアプリケーションが独自のものになります。実装の残りの詳細部分は、エンティティ・ベースのビュー・オブジェクトに組み込まれた機能によって処理されます。
注意:
行キーおよびエンティティ・キャッシュがトランザクションで果す役割について理解することは、エンティティ・ベースのビュー・オブジェクトの本質を明確にするために役立つ重要な概念です。これら2つの概念は、「ビュー・オブジェクトのデフォルト行セットを使用した操作のViewObjectインタフェース・メソッド」で説明します。
エンティティ・ベースのビュー・オブジェクトのインスタンスをアプリケーション・モジュールのデータ・モデルに追加した後、問合せの実行時に行われる処理を確認できます。読取り専用ビュー・オブジェクトの場合と同様、エンティティ・ベースのビュー・オブジェクトが標準のJDBC (Java Database Connectivity) APIを使用してデータベースにSQL問合せを直接送信し、データベースが結果セットを生成します。ただし、読取り専用ビュー・オブジェクトの場合とは異なり、エンティティ・ベースのビュー・オブジェクトは、データベースの結果セットの各行を取得するときに、関連付けられているエンティティ・オブジェクトの慣用名に基づいて行属性を分割します。この分割の際、各ビュー・オブジェクトのエンティティ・オブジェクトの慣用名に適切なタイプのエンティティ・オブジェクト行が作成され、問合せによって取得された関連属性がこれらのエンティティ行に移入され、このようなエンティティ行がそれぞれ個別のエンティティ・キャッシュに格納されます。これにより、データの複製コピーを格納するかわりに、ビュー行は、これを構成するエンティティ行部分を指し示すだけでになります。
図8-13は、エンティティ・キャッシュにより、2つのエンティティ・ベース・ビュー・オブジェクトの結果セット属性がどのように分割されるかを示しています。この例では、データベース結果セットで強調表示された行は、主キー112
のOrder
エンティティ行と、主キー301
のCustomerInfo
エンティティ行に分割されています。
「エンティティ・キャッシュがトランザクションで果す役割」で説明するように、findByPrimaryKey()
を使用してキャッシュに取り込んだエンティティ行には、エンティティ・オブジェクトのすべての属性が含まれています。一方、エンティティ・ベースのビュー・オブジェクトの問合せ結果の行を分割して作成されたエンティティ行には、問合せ結果に表れる属性の値のみが含まれます。これには完全な属性セットは含まれていません。このようにエンティティ行が部分的に移入されることにより、実行時のパフォーマンスが大幅に最適化されます。
一般的なエンタープライズ・アプリケーションで変更される行と比較して、取得される行の比率が非常に高くなるため、表示する必要がある属性のみをメモリーに読み込むことにより、常にすべての属性をメモリーに読み込む場合よりもメモリーを節約できます。
このような方法で問合せ結果のデータを基礎となるエンティティ行の構成要素部分に分割すると、現在のトランザクションが変更された場合、問い合せた結果のデータを含むすべての行で整合している結果が表示されるという、重要な利点が得られます。つまり、あるビュー・オブジェクトで顧客301
のPaymentType
属性を変更できる場合、顧客301
のPaymentType
属性を表示する任意のエンティティ・ベースのビュー・オブジェクトのすべての行が即座に更新され、変更が反映されます。顧客301
に関連付けられたデータがCustomerInfo
エンティティ・キャッシュで主キー301
を持つエンティティ行に格納されるのは1回のみであるため、オーダーのPaymentType
属性を問い合せたビュー行はどれも、この単一のエンティティ行を指し示すことになります。
このような実装の詳細は、ビュー・オブジェクトの行セット内の行を操作するクライアントに対しては完全に非表示にされます。クライアントは、ビュー行を操作して属性を取得して設定する際、これらの属性がその背後でどのようにエンティティ行に関連付けられているかには気付きません。
ユーザーがビュー行属性を変更しようとすると、基礎となるエンティティ行に応じてこのビュー行属性の変更を自動的に調整する一連の手順が実行されます。これらの手順により、エンティティ・マップ属性で定義された検証規則は、値が変更される前にトリガーされます。
図8-14は、ユーザーがエンティティ・マップされた属性を更新しようとするときに実行時に発生する基本的な手順を示しています。この例では、変更される属性Status
が、検証規則が定義されているエンティティ・オブジェクトの慣用名にマップされています。
ユーザーがStatus
属性の値をShip
に設定しようとします。
Status
はOrder
エンティティ・オブジェクトの慣用名にマップされた属性であるため、ビュー行は、Order
エンティティ・キャッシュ内で主キー112
を持つ、基礎となるエンティティ行に設定されている属性を委譲します。
Order
エンティティ・オブジェクトのStatus
属性に対する属性レベルの検証規則が評価され、規則が失敗した場合は変更が失敗します。
Status
属性の検証規則によってShipDate
属性がプログラム的に参照されるとします(たとえば、Order
は発注日と同日に出荷済にはできないというビジネス・ルールを適用する必要がある場合など)。ShipDate
は、問合せによって取得されたOrder
属性ではないため、Order
エンティティ・キャッシュ内に部分的に移入されたエンティティ行にはありません。
ビジネス・ルールでエンティティ・オブジェクトのすべての属性を常に参照可能にするため、エンティティ・オブジェクトはこの状況を検出し、主キーによって変更されるエンティティ行についてOrder
エンティティ・オブジェクト属性のセット全体を失敗にします(主キーはビュー・オブジェクトに適用される各エンティティ・オブジェクトの慣用名に表示されます)。
属性レベルの検証がすべて成功した後、エンティティ・オブジェクトでは、最初の属性の変更を許可する前にORDERS
表でこの行にロックをかけます。
この行をロックできた場合、行内のStatus
属性の設定が成功し、エンティティ行でこの値が変更されます。
注意:
jbo.locking.mode
構成プロパティは、行のロック方法を制御します。デフォルト値はoptimistic
です。通常、Fusion Webアプリケーションでは、このデフォルト設定のoptimistic
を使用するため、トランザクションのコミット時まで行はロックされません。pessimistic
ロック・モードの場合、エンティティ・キャッシュで行に対する変更を許可する前に行のロックを可能にする必要があります。
ユーザーが外部キーの属性を変更しようとすると、基礎となるエンティティ行に応じてこのビュー行属性の変更を自動的に調整する一連の手順が実行されます。これらの手順により、外部キーのエンティティ・マップ属性で定義された検証規則は、値が変更される前にトリガーされます。また、変更された外部キー属性のビュー行に、すべての参照されたエンティティ・オブジェクトの正しい属性が反映されます。
図8-15は、ユーザーが外部キーのエンティティ・マップ属性を更新しようとするときに実行時に発生する基本的な手順を示しています。この例では、変更される属性CustomerInfoId
は、エンティティ・オブジェクトの慣用名Order
にマップされており、ここでこの属性は別のエンティティ・オブジェクトであるCustomerInfo
と関連付けられます。
ユーザーがCustomerInfoId
属性の値を300
に設定しようとします。
CustomerInfoId
はOrder
エンティティ・オブジェクトの慣用名にマップされた属性であるため、ビュー行は、Order
エンティティ・キャッシュ内で主キー112
を持つ、基礎となるエンティティ行に設定されている属性を委譲します。
Order
エンティティ・オブジェクトのCustomerInfoId
属性に対する属性レベルの検証規則が評価され、規則が失敗した場合は変更が失敗します。
この行はすでにロックされているため、行内のCustomerInfoId
属性の設定が成功し、エンティティ行でこの値が変更されます。
Order
エンティティ・オブジェクトの慣用名のCustomerInfoId
属性は、CustomerInfo
エンティティ・オブジェクトに関連付けられているため、外部キー値をこのように変更すると、ビュー行で、顧客301
の現在のエンティティ行部分が、新しいCustomerInfoId = 300
に対応するエンティティ行に置き換えられます。これにより、オーダー112
のビュー行が300
のエンティティ行を指し示すよう効率的に変更できるため、ビュー行のPaymentType
の値が更新され、この新しく割り当てられた顧客の参照情報が正しく反映されます。
変更に問題がなく、トランザクションをコミットするとします。図8-16に示すとおり、次の2つの基本手順があります。
Transaction
オブジェクトにより、保留中の変更リスト内の無効なエンティティ行が検証されます。
保留中の変更リスト内のエンティティ行がデータベースに保存されます。
この図は、1つの変更済エンティティ・オブジェクトの検証処理が他のエンティティ・オブジェクトに対する変更にプログラム的に影響する前に行う、手順1のループを示します。保留中の変更リスト上で無効なエンティティのリストが処理された後、リストにまだエンティティが残されている場合、トランザクションで別のパスが実行されます。リストのパススルーは最大10回行われます。この時点でまだ無効なエンティティ行がある場合は通常、ビジネス・ロジックにエラーがあり、このビジネス・ロジックを調査する必要があるため、例外がスローされます。
ビュー・オブジェクトの問合せを再実行する場合、デフォルトでは、最新の結果セットを読み込むための準備中、現在の行セット内のビュー行は無視されます。ただし、このビュー・オブジェクト操作はエンティティ・キャッシュには直接影響しません。この場合、ビュー・オブジェクトがデータベースに対してSQLを送信することによってプロセスが再開され、データベースの結果セット行が取得され、エンティティ行部分に分割されます。
注意:
通常、ビュー・オブジェクトでデータの問合せを再実行する場合、この操作では最新のデータベース情報を取得します。かわりにビュー・オブジェクトの問合せ対象をキャッシュ内の既存のエンティティ行のみに制限する場合や、すでにビュー・オブジェクトの行セット内にある既存の行に制限して、データベースのラウンドトリップを回避する場合は、「行セットのメモリー内でのソート処理とフィルタ処理の実行」を参照してください。
問合せの再実行時におけるこのエンティティ行分割プロセスの一環として、エンティティ行の属性が変更されていない場合、エンティティ・キャッシュ内の値が更新され、新しい問合せ結果の値が反映されます。
一方、現在のトランザクションでエンティティ行属性の値が変更されている場合、問合せ再実行時のエンティティ行の分割プロセスでは、値はリフレッシュされません。現在のトランザクションでコミットされない変更はそのまま残されるため、エンド・ユーザーの論理作業ユニットは保持されます。任意のエンティティ属性値の場合と同様、これらの保留中の変更は、変更済エンティティ行を参照する任意のエンティティ・ベースのビュー・オブジェクト行に継続して表示されます。
注意:
エンド・ユーザーによる行の挿入および削除はエンティティ・キャッシュでも管理されるため、問合せの再実行時に、新規行を表示して削除済の行をスキップできます。新しい行の動作の詳細は、「同じエンティティに基づくビュー・オブジェクトでの新しい行の一貫性の保持」を参照してください。
たとえば、図8-17は、ユーザーがOrders
ビュー・オブジェクト・インスタンスを使用する別のページにドリルダウンし、オーダー112
に関する詳細を取得するシナリオを示しており、これは現在のトランザクションの保留中の変更のコンテキストで発生します。このビュー・オブジェクトには、プライマリOrders
の慣用名と、CustomerInfo
の参照の慣用名の、2つのエンティティ・オブジェクトの慣用名があります。問合せ結果がエンティティ行に分割されると、前のOrderInfo
ビュー行で変更されたものと同じOrder
エンティティ行を指し示すことになります。つまり、エンド・ユーザーには保留中の変更が正しく表示され、オーダーはこのトランザクションのsking
に割り当てられています。
図8-17 エンティティ・キャッシュにマージされる、個別ビュー・オブジェクトのエンティティ属性セット
2つの異なるビュー・オブジェクトが、参照情報の2つの異なるサブセットを取得でき、属性の一致するセットの有無にかかわらず、結果がマージされます。たとえば、図8-17もこの状況を示しており、Orders
ビュー・オブジェクトはユーザーのEmail
を問い合せていますが、OrderInfo
ビュー・オブジェクトはユーザーのPaymentOption
を問い合せています。この図は、実行時に行われる処理を示しており、取得した行を分割する際に、すでにキャッシュ内にある部分的に移入されたエンティティ行とは異なる属性セットがエンティティ行部分に含まれる場合、属性はマージされます。その結果、キャッシュ内の部分的に移入されたエンティティ行に、オーバーラップするユーザー属性のサブセットが統合されます。一方、キャッシュ内になかったjchen
(ユーザー302)の場合、新しいエンティティ行にはEmail
属性のみが含まれ、PaymentOption
は含まれません。
ビュー・オブジェクトには、SQLの実行方法とデータベースからデータをフェッチする方法を制御するチューニング・パラメータが用意されています。これらのチューニング・パラメータは、ビュー・オブジェクトの実行時パフォーマンスで重要な役割を果たします。アプリケーションでフェッチ・オプションが正常にチューニングされないと、ビュー・オブジェクトが必要以上の量のデータをフェッチし、データベースへのラウンドトリップの回数が非常に増える場合があります。
表8-2に示すように、概要エディタの「一般」ページの「チューニング」セクションでは、フェッチ・オプションを設定できます。
表8-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をチューニングするための次のオプションも用意されています。
バインド変数: ビュー・オブジェクトに関連付けられた問合せに、実行ごとに変更される可能性がある値が含まれる場合は、バインド変数を使用します。問合せでバインド変数を使用すると、データベースで問合せを再解析する必要なく、問合せを再実行できます。バインド変数は、ビュー・オブジェクトの概要エディタの「問合せ」ページでビュー・オブジェクトに追加できます。詳細は、「バインド変数の使用」を参照してください。
問合せオプティマイザ・ヒント: ビュー・オブジェクトでは、ヒントをデータベースに渡して、関連する問合せに使用される実行計画に影響を与えることができます。オプティマイザ・ヒントは、ビュー・オブジェクトの概要エディタの「チューニング」セクションの「データベースから取得」グループ・ボックスで指定できます。オプティマイザ・ヒントの詳細は、「必要に応じた問合せオプティマイザ・ヒントの指定」を参照してください。
クライアント・プログラムを使用してADFアプリケーション・モジュールをプラグラム的にテストします。
少なくとも1つのビュー・オブジェクト・インスタンスを含む、操作中のアプリケーション・モジュールをテストする準備ができたら、単純なテスト・クライアント・プログラムを構築して、含まれるビュー・オブジェクト・インスタンスにあるデータを使用したプログラムによる操作の基礎を示すことができます。
アプリケーション・モジュールのデータ・モデルにアクセスするクライアントの視点からは、読取り専用ビュー・オブジェクトを操作するAPIと、エンティティ・ベースのビュー・オブジェクトを操作するAPIは同一のものです。機能的な主な相違点は、エンティティ・ベースのビュー・オブジェクトでは、ビュー・オブジェクトのデータを完全に更新できる点です。エンティティ・ベースのビュー・オブジェクトを含むアプリケーション・モジュールは、作業ユニットを定義し、トランザクションを管理します。この項では、SummitADF_Examples
ワークスペースを操作するテスト・クライアント・プログラムを使用して次について説明します。
マスター/ディテール/ディテール階層の反復
行の検索および外部キー値の更新
新規注文の作成
行を識別する行キーの取得
oracle.jbo
パッケージのViewObject
インタフェースには、データ取得タスクを簡単に実行するメソッドが用意されています。例に使用されるこれらのメソッドの一部には、次のものが含まれます。
executeQuery()
: ビュー・オブジェクトの問合せを実行し、その結果の行セットを移入します。
setWhereClause()
: 実行時に動的条件を追加して検索を絞り込みます。
setNamedWhereClauseParam()
: 名前付きバインド変数の値を設定します。
hasNext()
: 行セット・イテレータが結果の最終行に到達したかどうかをテストします。
next()
: 行セット・イテレータを行セット内の次の行へ進めます。
getEstimatedRowCount()
: ビュー・オブジェクトの問合せが戻す行の数をカウントします。
ビュー・オブジェクトを操作する場合は、通常、単一の結果行セットのみを1回で操作します。このきわめて一般的なユースケースを単純化するために、図8-18に示すように、ビュー・オブジェクトにはデフォルトのRowSet
が含まれ、ここにデフォルトのRowSetIterator
が含まれています。デフォルトのRowSetIterator
により、デフォルト行セットに自動的に適用されることを認識しながら、ViewObject
コンポーネント自体でデータ取得メソッドのすべてを直接コールできるようになります。
図8-18 デフォルトのRowSetおよびRowSetIteratorが含まれているビュー・オブジェクト
注意:
「多相ビュー・オブジェクトの定義」では、単一のビュー・オブジェクトを使用して複数の異なる結果行セットを生成する状況が示されています。また、1つの行セットに対して複数の異なる行セット・イテレータを作成するシナリオも説明されています。ただし、多くの場合は単一のイテレータのみ必要です。
このガイドで「ビュー・オブジェクトの行を使用して操作中」という表現を使用した場合は、正確にはビュー・オブジェクトのデフォルト行セットの行を使用して操作するということを意味しています。同様に、「ビュー・オブジェクトの行全体で反復処理する」という表現は、正確にはビュー・オブジェクトのデフォルト行セットのデフォルト行セット・イテレータを使用して、その行をループするという意味です。
ビュー行を操作するときは、oracle.jbo
パッケージの中のRow
インタフェースを使用します。図8-19に示すように、このインタフェースには、任意の行を識別するKey
オブジェクトへのアクセスに使用できる、getKey()
と呼ばれるメソッドが含まれています。Row
インタフェースは、oracle.jbo.server
パッケージ内の Entity
インタフェースによって拡張されます。この関係は、エンティティ行という用語が適切であることの具体的な理由になります。エンティティ行がビジネス・ロジックのカプセル化やデータベース・アクセスの処理のための追加機能をサポートしている場合でも、エンティティ行はRow
としてそのまま扱うことができます。
エンティティ・ベースのビュー・オブジェクトは、キーによる行の検索タスクを、基礎となるエンティティ行部分に委譲します。
前述のとおり、ビュー行とエンティティ行はどちらも単一属性または複数属性のキーをサポートしているため、特定のRow
に関連付けられたKey
オブジェクトにより、キーを構成するすべての属性がカプセル化されます。Key
オブジェクトがある場合は、任意の行セットに対してfindByKey()
メソッドを使用して、Key
オブジェクトに基づいて行を検索できます。findByKey()
メソッドを使用してキーによってビュー行を検索すると、ビュー行ではエンティティ定義のfindByPrimaryKey()
メソッドを使用して、ビュー行キーに属性を提供する各エンティティ行が検索されます。
読取り専用ビュー・オブジェクトの場合、このタスクを委譲する基礎となるエンティティ行がないため、主キー属性が1つでも検出されると、ビュー・オブジェクトの実装により、manageRowsByKey
フラグが自動的に有効になります。このため、読取り専用ビュー・オブジェクトの場合は、findByKey()
メソッドが成功します。manageRowsByKey
フラグが有効でない場合、キーを使用して現在の行を設定するなどのUI操作は、findByKey()
メソッドに依存するため機能しません。
注意:
エンティティ・ベースのビュー・オブジェクトを定義する場合、デフォルトでは、すべてのエンティティ・オブジェクトの慣用名の主キー属性は、「キー属性」プロパティの設定がtrue
としてマークされます。更新不可能な参照エンティティ・オブジェクトの慣用名では、キー属性の「キー属性」プロパティを無効にしてください。更新可能なエンティティ・オブジェクトの慣用名の主キーに関連するビュー・オブジェクト属性は、複合ビュー行キーの一部である必要があるため、「キー属性」プロパティを無効にできません。
アプリケーション・モジュールは、論理的な作業ユニットのトランザクション・コンテナです。実行時には、指定された名前の構成情報を使用してデータベース接続を確立し、トランザクション管理を付属のTransaction
オブジェクトに委譲します。論理作業ユニットには、様々なタイプの複数のエンティティ行の検索や変更が含まれる場合があるため、Transaction
オブジェクトには、現在のユーザーのトランザクションに関連するエンティティ行を保持するための作業領域として、エンティティ・キャッシュが用意されています。各エンティティ・キャッシュには単一のエンティティ・タイプの行が含まれるため、2つ以上のエンティティ・オブジェクトが関連するトランザクションでは、これらのエンティティ行の作業用コピーが個別キャッシュに保持されます。
エンティティ・オブジェクトの関連エンティティ定義を使用して、アプリケーション・モジュールで既存のエンティティ行を検索し、変更するためのコードを記述できます。図8-20に示すとおり、Order
エンティティ・オブジェクトのエンティティ定義に対してfindByPrimaryKey()
をコールすると、そのキーを持つ行を取得できます。この行がまだエンティティ・キャッシュ内にない場合、エンティティ・オブジェクトによってこの行をデータベースから取得するための問合せが実行されます。この問合せにより、基礎となる表からエンティティ・オブジェクトのすべての持続属性が選択され、エンティティ・オブジェクトの主キー属性に対応する列に適したWHERE
句を使用して行が検索されます。同一トランザクション中に同じエンティティ行をキーによって引き続き検索する場合、この行をキャッシュ内で検索することにより、データベースへのトリップを回避します。特定のエンティティ・キャッシュでは、主キーによってエンティティ行が索引付けされます。これにより、キャッシュ内でのエンティティ行の検索処理が速くなります。
アソシエーション・アクセッサ・メソッドを使用して関連エンティティ行にアクセスする場合、これらの行はエンティティ・キャッシュからも取得されます。関連エンティティ行がキャッシュ内にない場合は、データベースから取得されます。最後に、エンティティ・キャッシュは、新しいエンティティ行が保存されるまで保持される場所でもあります。つまり、createInstance2()
メソッドを使用してエンティティ定義に対して新しいエンティティ行を作成する場合、このエンティティ行はエンティティ・キャッシュに追加されます。
エンティティ行を作成、変更または削除すると、このエンティティ行はトランザクションの保留中の変更リストに自動的に登録されます。Transaction
オブジェクトに対してcommit()
をコールすると、保留中の変更リストが処理され、まだ無効の新規または変更済エンティティ行があるかどうかが検証されます。保留リスト内のエンティティ行がすべて有効である場合、Transaction
により、データベースのSAVEPOINT
が発行され、データベースへのエンティティ行の保存が調整されます。すべて正常に完了すると、最終的にデータベースのCOMMIT
文が発行されます。問題が発生した場合、Transaction
によってROLLBACK TO SAVEPOINT
が実行され、ユーザーはエラーを修正するか、または再試行できるようになります。
アプリケーション・モジュールで使用されるTransaction
オブジェクトは、単一のエンド・ユーザー・トランザクション用のエンティティ行の作業セットです。設計上、これは共有のグローバル・キャッシュではありません。データベース・エンジン自体は、複数の同時ユーザーを対象とした非常に効率的な共有グローバル・キャッシュです。ADFビジネス・コンポーネントでは、すべての作業で行われてきたデータベースの共有グローバル・キャッシュ機能の微調整を繰り返すのではなく、その結果が意識的に採用されています。refresh()
メソッドをコールすると、データベースから単一のエンティティ・オブジェクトのデータをいつでもリフレッシュできます。Transaction
オブジェクトに対してsetClearCacheOnCommit()
またはsetClearCacheOnRollback()
を使用すると、コミットまたはロールバック時にエンティティ・キャッシュを消去するかどうかを制御できます。デフォルトはそれぞれfalse
とtrue
です。また、Transaction
オブジェクトにはclearEntityCache()
メソッドも用意されており、このメソッドを使用して、特定のエンティティ・タイプ(またはすべてのタイプ)のエンティティ行をプログラムで消去できます。エンティティ・キャッシュを消去すると、そのタイプのエンティティ行は、主キーによって次に検出されるか、エンティティ・ベースのビュー・オブジェクトによって取得されるときに、データベースから取得できます。
テスト・クライアント・プログラムを作成するには、「新規ギャラリ」からアクセス可能な「Javaクラスの作成」ウィザードを使用します。
テスト・クライアント・プログラムを作成するときに「Javaクラスの作成」ウィザードを使用すると、プログラム・ファイルがソース・エディタで開き、事前定義済のコード・テンプレートからコードを追加してテスト・クライアントを作成することができます。
始める前に:
プログラムによるテストに関する知識が役立つ場合があります。詳細は、「ビュー・オブジェクト・インスタンスのプログラムによるテスト」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
スケルトンJavaテスト・クライアントを作成するには:
package oracle.summit.model.test; public class TestClient { public static void main(String[] args) { TestClient testClient = new TestClient(); } }
テスト・クライアントのスケルトン・コードを作成したら、作成したスケルトン・コード・テンプレートを使用してファイルの編集を開始できます。
始める前に:
プログラムによるテストに関する知識が役立つ場合があります。詳細は、「ビュー・オブジェクト・インスタンスのプログラムによるテスト」を参照してください。
他のOracle ADF機能を使用して追加できる機能を理解しておくことも役立ちます。詳細は、「ビュー・インスタンスのテストの追加機能」を参照してください。
次のタスクを完了する必要があります。
スケルトン・コードを挿入するには:
アプリケーション・モジュールに対するスケルトン・テスト・クライアントには、次の例に示すようなソース・コードが含まれている必要があります。
注意:
「アプリケーション・モジュールのクライアント・インタフェースのプログラム的操作」における例では、このテスト・クライアント・サンプルコードが拡張され、カスタム・アプリケーション・モジュール・サービス・メソッドのコールも説明されます。
package oracle.summit.model.viewobjects; 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.summit.model.viewobjects.AppModule"; String config = "AppModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); // 1. Find the Customer view object instance. ViewObject customerList = am.findViewObject("SCustomerView1"); // Work with your appmodule and view object here Configuration.releaseRootApplicationModule(am,true); } }
メソッド・コールcreateRootApplicationModule()
により、テスト・クライアントは、ADFモデル・レイヤーが使用できない場所でアプリケーション・モジュール・インスタンスを作成できます。通常、Fusion Webアプリケーションでは、コードはADFバインディング・オブジェクトを介してアプリケーション・モジュール上のビュー・オブジェクトを見つけます。ADFモデル・レイヤーの操作方法の詳細は、「Fusion Webアプリケーションでのアプリケーション・モジュール・クライアント・インタフェースへのアクセス方法」を参照してください。
// Work with your appmodule and view object here
を、テスト対象のビュー・オブジェクトを実行するコードに置き換えます。たとえば、ビュー・オブジェクトの問合せを実行して戻される行数を表示し、結果をループしてデータをフェッチし、コンソールに出力するには、次の例に示すコードを、使用しているデータ・モデル・プロジェクトのコンポーネントに合うように変更します。
// 2. Execute the query customerList.executeQuery(); // 3. Iterate over the resulting rows while (customerList.hasNext()) { Row customer = customerList.next(); // 4. Print the customer's name System.out.println("Customer: " + customer.getAttribute("Name")); // 5. Get related rowset of Orders using view link accessor attribute RowSet orders = (RowSet)customer.getAttribute("SOrdView"); // 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("CustomerId")+"] "+ order.getAttribute("Id")+": "+ order.getAttribute("Total")); if(!order.getAttribute("OrderFilled").equals("Y")) { // 8. Get related rowset of OrderItems RowSet items = (RowSet)order.getAttribute("SItemView"); // 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("ItemId")+": "+ item.getAttribute("Price")); } } } }
最初の行では、executeQuery()
メソッドをコールして、ビュー・オブジェクト問合せを実行します。これにより、ビュー・オブジェクトのhasNext()
メソッドがfalse
を戻すまで反復処理を行うwhile
文を使用してループできる、ゼロまたは1行以上の行セットを生成します。ループ内では、コードで現行のRow
をcustomer
という変数に入れてから、この現在のRow
オブジェクト上でgetAttribute()
メソッドを2回コールし、Name
属性とOrders
属性の値を取得して、オーダー情報をコンソールに出力します。2番目のwhile
文では、オーダーの明細項目に対して同じタスクを実行します。
Configuration
オブジェクトでのcreateRootApplicationModule()
へのコールによって、使用するアプリケーション・モジュールのインスタンスが戻されます。デバッグ診断出力で示されるとおり、ADFビジネス・コンポーネント・ランタイム・クラスによって、必要に応じてXMLドキュメントがロードされ、設計時にデータ・モデルで定義されたアプリケーション・モジュールとビュー・オブジェクト・コンポーネントのインスタンスがインスタンス化されます。アプリケーション・モジュール上のfindViewObject()
メソッドによって、アプリケーション・モジュールのデータ・モデルからビュー・オブジェクト・インスタンスを名前で検索します。「スケルトン・コードの変更によるテスト・クライアントの作成」で示されているループの後、テスト・クライアントはConfiguration
オブジェクトでreleaseRootApplicationModule()
を実行します。これにより、アプリケーション・モジュールを使用して処理したことが通知され、アプリケーション・モジュールに使用されたデータベース接続のように、フレームワークでリソースをクリーン・アップできるようになります。
createRootApplicationModule()
およびreleaseRootApplicationModule()
メソッドは、アプリケーション・モジュール・コンポーネントへのコマンド行アクセスの場合に非常に便利です。ただし、通常、ADFベースのWebアプリケーションのコンテキストでは、これら2行のコードを記述する必要はありません。このような場合は、ADFモデル・レイヤーとADFビジネス・サービス・レイヤーの自動的な連携により、ADFアプリケーション・モジュール・コンポーネントが取得およびリリースされます。ADFモデル・レイヤーの操作方法の詳細は、「Fusion Webアプリケーションでのアプリケーション・モジュール・クライアント・インタフェースへのアクセス方法」を参照してください。
getEstimatedRowCount()
メソッドは、含まれている行数を判断するために、RowSet
で使用されます。
long numOrders = orders.getEstimatedRowCount();
getEstimatedRowCount()
の実装によって最初にSELECT COUNT(*)
の問合せが発行され、問合せから戻される行の数を計算します。問合せは、次のような文のビュー・オブジェクトの問合せ全体をラップすることにより、計算式で表されます。
SELECT COUNT(*) FROM ( ... your view object's SQL query here ... )
SELECT COUNT(*)
問合せを使用すると、必ずしもすべての行自体を取得しなくても、ビュー・オブジェクトの行数にアクセスできるようになります。このアプローチにより、大量の行数を戻す問合せを操作する場合や、問合せの結果を操作する前に問合せから戻さうる行数をテストする場合に、重要な最適化を図ることができます。
推定行数が計算されると、後続のメソッドへのコールではCOUNT(*)
問合せは再実行されません。この値は、次にこのビュー・オブジェクトの問合せが実行されるまでキャッシュされます(データベースから戻される新しい問合せ結果セットに、前回の問合せ実行時より多い、少ない、または異なる行が含まれる可能性があるためです)。推定行数は、現行トランザクションで保留中の変更、関連する新規行の数の追加、および戻された数から削除された行数の差引を考慮して自動的に調整されます。
getEstimatedRowCount()
をオーバーライドして、アプリケーションの必要性に合せて、カスタムのカウント問合せを実行することもできます。
「ビュー・リンク・アクセッサを使用したディテール・コレクションへのプログラムによるアクセス」で説明しているように、ビュー・リンク・アクセッサを使用してディテール行のRowSet
を取得すると、ビュー・オブジェクトの結果行セットで使用されるパターンと同じパターンを使用して、その行セットに含まれる行全体をループできます(次の例を参照)。
while (orders.hasNext()) { Row curOrder = orders.next(); System.out.println("--> (" + curOrder.getAttribute("Id") + ") " + curOrder.getAttribute("Total")); }
次の例は、CustomerView
ビュー・オブジェクト・インスタンスを制限してcredit_rating_id
の値が4
であるユーザーのみを表示するために、動的なWHERE
句を設定するmain()
メソッドを示しています。さらに、executeAndShowResults()
メソッドは、ビュー・リンク・アクセッサ属性(SOrdView
)にアクセスし、各顧客のオーダーのId
およびTotal
属性を出力します。
ビュー・リンク・アクセッサを使用してディテール・コレクションにアクセスするには、次の基本手順に従います(後に例を示しています)。
マスター・ビュー・オブジェクト・インスタンスを検索します。
問合せを実行します。
マスター・ビュー・オブジェクトの行を反復処理します。
ビュー・リンク・アクセッサ属性を使用して、関連するディテール・ビュー・オブジェクトの行セットを取得します。
ディテール・ビュー・オブジェクトの行を反復処理します。
必要に応じて、ディテール行セット属性を操作します。
パフォーマンスのヒント:
行をループするために記述するコードで行を表示する必要がない場合は、終了した行セットでcloseRowSet()
メソッドをコールできます。この方法では、メモリー使用を効率化できます。行セットの問合せは、その行セットに次にアクセスしたときに再実行されます。
package oracle.summit.model.viewobjects; 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.summit.model.viewobjects.AppModule"; String config = "AppModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); ViewObject vo = am.findViewObject("SCustomerView1"); // Add an extra where clause with a new named bind variable vo.setWhereClause("credit_rating_id = :theCreditRating"); vo.defineNamedWhereClauseParam("theCreditRating", null, null); vo.setNamedWhereClauseParam("theCreditRating", "4"); // Show results when :theCreditRating = '4' executeAndShowResults(vo); Configuration.releaseRootApplicationModule(am, true); } private static void executeAndShowResults(ViewObject vo) { System.out.println("---"); vo.executeQuery(); while (vo.hasNext()) { Row curCustomer = vo.next(); // Access the row set of details using the view link accessor attr. RowSet orders = (RowSet)curCustomer.getAttribute("SOrdView"); long numOrders = orders.getEstimatedRowCount(); System.out.println(curCustomer.getAttribute("Id") + " " + curCustomer.getAttribute("Name")+" ["+ numOrders+" orders]"); while (orders.hasNext()) { Row curOrder = orders.next(); System.out.println("--> (" + curOrder.getAttribute("Id") + ") " + curOrder.getAttribute("Total")); } } } }
TestClient2.java
を実行すると、次の例に示すような出力が「ログ」ウィンドウに出力されます。各顧客がリストされ、オーダーのある顧客ごとに、オーダーのIDと合計が顧客名の下に表示されます。
--- 202 Simms Athletics [11 orders] --> (98) 595 --> (113) 4990 --> (114) 567 --> (115) 866.7 --> (116) 3661.24 --> (117) 17489 212 Hamada Sport [22 orders] --> (108) 149570 --> (196) 761 --> (197) 516.75 ...
デバッグ診断を有効にしてTestClient2.java
を実行すると、ビュー・オブジェクトによって実行されたSQL問合せが表示されます。ビュー・リンクのWHERE
句条件は、CustomerView
ビュー・オブジェクトで現在行のディテール・サービス・リクエスト行のフィルタリングを自動実行するために使用されます。
別のネスト・レベルが含まれるマスター/ディテールの反復処理を行うには、次の基本手順に従います(後に例を示しています)。
マスター・ビュー・オブジェクト・インスタンスを検索します。
問合せを実行します。
結果の行を反復処理します。
必要に応じて、マスター行セット属性を操作します。
ビュー・リンク・アクセッサ属性を使用して、関連するディテール・ビュー・オブジェクトの行セットを取得します。
ディテール行セットの行を反復処理します。
必要に応じて、ディテール行セット属性を操作します。
ビュー・リンク・アクセッサ属性を使用して、関連する2番目のディテール・ビュー・オブジェクトの行セットを取得します。
2番目のディテール・行セットの行を反復処理します。
必要に応じて、2番目のディテール行セット属性を操作します。
次の例では、もう1つネスト・レベルが追加されている以外は、「ビュー・リンク・アクセッサを使用したディテール・コレクションのアクセス方法」で説明した、マスター/ディテール読取り専用ビュー・オブジェクトを反復するTestClient
プログラムと同じAPIを使用しています。
既存のTestClient.java
クラスでJDeveloperの「リファクタ」→「複製」機能を使用する場合、それを簡単にクローニングしてTestClient2.java
クラスを作成できます。たとえば、「ビュー・リンク・アクセッサを使用したディテール・コレクションのアクセス方法」で説明しているTestClient.java
クラスはこの手法に適しています。
package oracle.summit.model.viewobjects; 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) { TestClient testClient = new TestClient(); String amDef = "oracle.summit.model.viewobjects.AppModule"; String config = "AppModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef,config); // Work with your appmodule and view object here // 1. Find the Customer view object instance. ViewObject customerList = am.findViewObject("SCustomerView1"); // 2. Execute the query customerList.executeQuery(); // 3. Iterate over the resulting rows while (customerList.hasNext()) { Row customer = customerList.next(); // 4. Print the person's email System.out.println("Customer: " + customer.getAttribute("Name")); // 5. Get related rowset of Orders using view link accessor attr. RowSet orders = (RowSet)customer.getAttribute("SOrdView"); // 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("CustomerId")+"] "+ order.getAttribute("Id")+": "+ order.getAttribute("Total")); if(order.getAttribute("OrderFilled").equals("Y")) { // 8. Get related rowset of Items RowSet items = (RowSet)order.getAttribute("SItemView"); // 9. Iterate over the Items rows while (items.hasNext()) { Row item = items.next(); // 10. Print out some order items attributes System.out.println(" "+ item.getAttribute("ItemId")+": $"+ item.getAttribute("Price")); } } } } } }
このプログラムを実行すると、次の例に示す出力が生成されます。
Customer: Unisports [201] 97: 84000 210: $9 211: $1500 Customer: Simms Athletics [202] 98: 595 212: $85 [202] 113: 4990 328: $9 [202] 114: 567 329: $28 330: $40.95 331: $25 ...
行を検索して外部キーの値を更新するには、次の基本手順に従います(後に例を示しています)。
ビュー・オブジェクト・インスタンスを検索します。
Key
オブジェクトを作成し、ビュー・インスタンスの行を参照します。
findByKey()
を使用して行を検索します。
必要に応じて、行の属性を操作します。
次の例は、外部キーの値を検索して更新し、Orders
ビュー・オブジェクト・インスタンスの行を検索するmain()
メソッドを示しています。このサンプルでは、行の値が変更される前に、既存のOrderStatusCode
属性の値が出力されます。
package oracle.summit.model.viewobjects; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import oracle.jbo.ApplicationModule; import oracle.jbo.JboException; import oracle.jbo.Key; import oracle.jbo.Row; import oracle.jbo.RowSet; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; public class TestClient3 { public TestClient3() { super(); } public static void main(String[] args) { String amDef = "oracle.summit.model.viewobjects.AppModule"; String config = "AppModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); // 1. Find the Orders view object instance ViewObject vo = am.findViewObject("SOrdView1"); // 2. Construct a new Key to find Order # 100 Key orderKey = new Key(new Object[] { 100 }); // 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 Date dateOrdered = (Date) order.getAttribute("DateOrdered"); String orderDate = dateOrdered.toString(); System.out.println("Order Date is: " + orderDate); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Calendar c = Calendar.getInstance(); try { c.setTime(sdf.parse(orderDate)); } catch (ParseException e) { } c.add(Calendar.DAY_OF_MONTH, -2); // // number of days to add orderDate = sdf.format(c.getTime()); System.out.println(orderDate); try { // 5. Try setting the ship date to an illegal value order.setAttribute("DateShipped", orderDate); am.getTransaction().commit(); } catch (JboException ex) { System.out.println("ERROR: " + ex.getMessage()); } // 6. Set the ship date to a legal value order.setAttribute("DateShipped", orderDate); // 7. Show the value of the ship date was updated successfully System.out.println("Ship date is: " + order.getAttribute("DateShipped")); // 8. Show the current value of the customer for this order System.out.println("Customer: " + order.getAttribute("CustomerId")); // 9. Reassign the order to customer # 210 order.setAttribute("CustomerId", 210); // 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); } }
この例を実行すると、次の例に示す出力が生成されます。
Order Date is: 2012-08-29 2012-08-27 ERROR: JBO-oracle.summit.model.viewobjects.SOrd_Rule_0: You cannot have a shipping date that is before the order date Ship date is: 2012-08-27 Customer: 204 Customer: 210 Transaction canceled
新しいビュー行インスタンスを作成するには、次の基本手順に従います(後に例を示しています)。
ビュー・オブジェクト・インスタンスを検索します。
新しい行を作成し、行セットに挿入します。
新しい行の必須属性の値を設定します。
トランザクションをコミットします。
次の例は、OrdView
ビュー・オブジェクト・インスタンスを検索し、新しい行を行セットに挿入するmain()
メソッドを示しています。OrdView
ビュー・オブジェクトはエンティティ・ベースなので、CreatedBy
属性は、マップされたエンティティ・オブジェクト属性から値を導出します。このサンプルでは、トランザクションのコミット前に、残りの属性の値が設定されます。
package oracle.summit.model.viewobjects; import java.util.Date; import oracle.jbo.ApplicationModule; import oracle.jbo.Row; import oracle.jbo.ViewObject; import oracle.jbo.client.Configuration; import oracle.jbo.domain.DBSequence; public class TestClient4 { public static void main(String[] args) { String amDef = "oracle.summit.model.viewobjects.AppModule"; String config = "AppModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); // 1. Find the Orders view object instance. ViewObject orders = am.findViewObject("SOrdView1"); // 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 DateOrdered attribute System.out.println("DateOrdered defaults to: " + newOrder.getAttribute("DateOrdered")); // 3. Set values for some of the required attributes newOrder.setAttribute("CustomerId", 201); newOrder.setAttribute("SalesRepId", 12); newOrder.setAttribute("PaymentTypeId", 2); newOrder.setAttribute("OrderFilled", "N"); // 4. Commit the transaction am.getTransaction().commit(); // 5. Retrieve and display the trigger-assigned order id DBSequence id = (DBSequence)newOrder.getAttribute("Id"); System.out.println("Thanks, reference number is " + id.getSequenceNumber()); Configuration.releaseRootApplicationModule(am, true); } }
この例を実行すると、次の例に示す結果が生成されます。
DateOrdered defaults to: 2013-3-11 Thanks, reference number is 6
行キーを取得して行を特定するには、次の基本手順に従います(後に例を示しています)。
ビュー・オブジェクト・インスタンスを検索します。
指定された値を使用してキーを作成します。
このキーを使用して行を検索します。
必要に応じて、行のキーを操作します。
次の例は、OrdView
ビュー・オブジェクト・インスタンスを検索し、行キーを作成してオーダー番号を検索するmain()
メソッドを示しています。findByKey()
メソッドでは、指定されたキーによりOrdView
行が検索されます。このサンプルでは、次に行のキーが表示され、ItemView
ビュー・リンク・アクセッサを使用して行セットがアクセスされ、行を反復処理して各ItemView
行のキーが表示されます。
package oracle.summit.model.viewobjects; 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 TestClient5 { public static void main(String[] args) { String amDef = "oracle.summit.model.viewobjects.AppModule"; String config = "AppModuleLocal"; ApplicationModule am = Configuration.createRootApplicationModule(amDef, config); // 1. Find the Orders view object instance ViewObject vo = am.findViewObject("SOrdView1"); // 2. Construct a key to find order number 100 Key orderKey = new Key(new Object[] { 100 }); // 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("SItemView"); // 6. Iterates over the Items row while (items.hasNext()) { Row itemRow = items.next(); // 4. Displays the key of each Items 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(); } }
この例を実行すると、次の例に示す結果が生成されます。シリアライズされたキーの文字列フォーマットは16進数で、キー内のすべての属性を示す単一文字列に情報が含まれています。
Key (100) has string format 000100000003313030 Key (100,156) has string format 000200000003C2020200000002C102 Key (100,157) has string format 000200000003C2020200000002C102 ...
複数のエンティティ・オブジェクトの慣用名に基づくビュー・オブジェクトでは、部分的に移入されたキーを指定してビュー行を検索できます。部分キーは、複数属性のKey
オブジェクトで、一部の属性がnull
に設定されたものです。ただし、findByKey()
を実行するために使用できる部分キーの種類には、厳密な規則があります。
ビュー・オブジェクトがn個のエンティティ・オブジェクトの慣用名(n > 1)に基づいている場合、ビュー行のキーは、デフォルトで、関連するすべてのエンティティ・オブジェクトの慣用名のすべての主キー属性で構成されます。ビュー行のキーに参加する必要があるのは最初のエンティティ・オブジェクトの主キーのみですが、デフォルトですべての主キーが使用されます。
一部のセカンダリ・エンティティ・オブジェクトの慣用名のキー属性をビュー行レベルのキー属性として残す場合は、そのエンティティ・オブジェクトの主キーを構成するすべての属性をビュー行のキーの一部として残しておく必要があります。n個のエンティティ・オブジェクトの慣用名のうちのm
個について(m <= n)、ビュー行の1つ以上のキー属性を残した場合、findByKey()
を使用し、m個のエンティティ・オブジェクトの慣用名の任意のサブセットに基づいて行を検索できます。Key
オブジェクトで値を指定するそれぞれのエンティティ・オブジェクトの慣用名について、そのエンティティの主キーのすべての属性にNULLではない値を指定する必要があります。
ビュー・オブジェクトが1つ以上のエンティティ・オブジェクトの慣用名に基づいている場合、そのfindByKey()
メソッドは、ビュー行キーでの属性がNULLではない最初のエンティティ・オブジェクトの慣用名に対応するエンティティ定義のfindByPrimaryKey()
メソッドに委譲することで行を検索するため、この規則に従う必要があります。エンティティ定義のfindByPrimaryKey()
メソッドでキャッシュ内のエンティティ行を検索するには、特定のエンティティ・オブジェクトに対するすべてのキー属性がNULL以外である必要があります。
具体的な例としては、OrderInfoVO
ビュー・オブジェクトで、OrderEO
エンティティ・オブジェクトがそのプライマリ・エンティティ・オブジェクト慣用名で、AddressEO
エンティティがセカンダリ参照エンティティ・オブジェクト慣用名である場合を考えてみてください。さらに、次の両方のビュー行属性のキー属性プロパティを、true
に設定したままにするものとします。
OrderId
- OrderEO
エンティティの主キー
AddressId
- AddressEO
エンティティの主キー
したがって、ビュー行のキーは、OrderId
とAddressId
の組合せになります。findByKey()
を呼び出すときは、次のような内容のKey
オブジェクトを渡すことができます。
基礎となるOrderEO
エンティティの完全に指定されたキー
Key k = new Key(new Object[]{new Number(200), null});
基礎となるAddressEO
エンティティの完全に指定されたキー
Key k = new Key(new Object[]{null, new Number(118)});
両方のエンティティの完全に指定されたキー
Key k = new Key(new Object[]{new Number(200), new Number(118)});
有効な部分キーを指定すると、findByKey()
メソッドは、キー・オブジェクトで指定されていないエンティティ・オブジェクト慣用名の属性をワイルドカードとして扱い、結果として複数の行を返すことができます。
アプリケーションに対してADFセキュリティを有効にし、テスト・ユーザーにjazn-data.xml
ファイルをプロビジョニングしている場合は、テスト・クライアントを実行する前に、ユーザーを認証するためのメソッド・コールを組み込む必要があります。テスト・クライアントでユーザーを認証するには、次の基本的な手順に従います(次の例を参照)。
認証サービスを作成します。
jazn-data.xml
ファイルに定義されている、テスト・ユーザー用のログイン資格証明を渡します。
認証が成功したら、アプリケーション・モジュールをテストします。
ユーザーをログアウトします。
ADFセキュリティの構成ウィザードを実行してADFセキュリティを有効にする方法、およびJDeveloperのアイデンティティ・ストアにテスト・ユーザーを作成する方法の詳細は、「ADFセキュリティ・プロセスの概要」を参照してください。
package oracle.summit.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); } } }