| Oracle® Fusion Middleware Oracle Application Development Framework Fusion開発者ガイド 11gリリース1(11.1.1.9.0) B52028-07 |
|
![]() 前 |
![]() 次 |
この章では、ADFエンティティ・オブジェクトを使用して、Oracle Application Development Framework (Oracle ADF)アプリケーションでビジネス・ドメインについて記述しているJavaオブジェクトの再使用可能なビジネス・レイヤーを作成する方法について説明します。
この章には次の項が含まれます:
エンティティ・オブジェクトは、指定したデータ・ソース内の行を表し、関連付けられた属性の変更を簡略化するためのADFビジネス・コンポーネントのコンポーネントです。重要なことは、エンティティ・オブジェクトを使用すると、ドメイン・ビジネス・ロジックをカプセル化できるため、ビジネス・ポリシーおよびビジネス・ルールを一貫性のある方法で検証できるということです。
エンティティ・オブジェクトは、データの有効性を強化するために様々な宣言的ビジネス・ロジック機能をサポートしています。通常、追加のカスタム・アプリケーション・ロジックおよびビジネス・ルールで宣言的な検証に補完することにより、各エンティティ・オブジェクトに最大の量のドメイン・ビジネス・ロジックを効率的にカプセル化します。関連付けられた一連のエンティティ・オブジェクトによって、複数のアプリケーションで活用できる再利用可能なビジネス・ドメインが形成されます。
エンティティ・オブジェクトの主要な概念は次のとおりです。
エンティティ・オブジェクトを定義するには、エンティティ・オブジェクトが示す行が含まれるデータベース表を指定します。
エンティティ・オブジェクト間の関連を反映するアソシエーションを作成できます。
実行時には、エンティティ行は関連するエンティティ定義オブジェクトによって管理されます。
各エンティティ行は、関連する行キーによって識別されます。
エンティティ行は、データベース・トランザクションを提供するアプリケーション・モジュールのコンテキストで取得および変更します。
すでに使用しているデータベース・スキーマがある場合、エンティティ・オブジェクトおよびアソシエーションを作成する最も簡単な方法は、これらを既存の表からリバース・エンジニアリングする方法です。必要な場合には、エンティティ・オブジェクトを最初から作成し、後でこのエンティティ・オブジェクト用の表を生成することもできます。
1つ以上のエンティティ・オブジェクトを作成するには、「新規ギャラリ」で使用できる「表からのビジネス・コンポーネント」ウィザードを使用します。
既存の表から1つ以上のエンティティ・オブジェクトおよびアソシエーションを作成するには:
アプリケーション・ナビゲータで、エンティティ・オブジェクトを作成するプロジェクトを右クリックし、「新規」を選択します。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」を選択してから「表からのビジネス・コンポーネント」を選択し、「OK」をクリックします。
これがプロジェクトで作成する最初のコンポーネントである場合、「ビジネス・コンポーネント・プロジェクトの初期化」ダイアログが表示され、データベース接続を選択できます。
「ビジネス・コンポーネント・プロジェクトの初期化」ダイアログで、データベース接続を選択するか、「新規」を選択して接続を作成します。「OK」をクリックします。
「エンティティ・オブジェクト」ページで、次の操作を実行してエンティティ・オブジェクトを作成します。
すべてのエンティティ・オブジェクトが作成されるパッケージ名を入力します。
「使用可能」リストからエンティティ・オブジェクトを作成する表を選択します。
「自動問合せ」チェック・ボックスを選択すると、使用可能な表のリストが即座に表示されます。必要に応じて、「名前フィルタ」フィールドで表名またはその一部を入力して、使用可能な表をリアルタイムでフィルタ処理できます。自動問合せ機能を使用するかわりに、「問合せ」ボタンをクリックしてオプションの表の名前フィルタに基づいてリストを取得することもできます。名前フィルタが入力されていない場合は、JDeveloperにより、選択したスキーマに対するすべての表オブジェクトが取得されます。
使用可能なデータベース・オブジェクトのうち、サブセットのみを表示する場合は、「フィルタ・タイプ」をクリックします。表、ビューまたはシノニムをフィルタ処理できます。
「使用可能」リストから表を選択した後、「選択済」リストに、この表について提案されるエンティティ・オブジェクト名とともに、関連する表名がカッコで囲まれて表示されます。
「選択済」リストでエンティティ・オブジェクト名を選択すると、「エンティティ名」フィールドを使用してデフォルトのエンティティ・オブジェクト名を変更できます。
|
ベスト・プラクティス: 各エンティティ・オブジェクト・インスタンスは特定の表の単一行を表しているため、エンティティ・オブジェクトの名前には、複数形の名詞ではなく、単数形の名詞(Address、Order、Personなど)を使用してください。図4-1に、FODスキーマでADDRESSES表を選択し、パッケージ名としてoracle.fodemo.storefront.entitiesを設定し、エンティティ・オブジェクトの名前を単数形に変更した後のウィザード・ページを示します。 |
目的の表オブジェクトとそれに対応するエンティティ・オブジェクトの名前を選択したら、「終了」をクリックします。
アプリケーション・ナビゲータには、指定したパッケージ内のエンティティ・オブジェクトが表示されます。
|
ベスト・プラクティス: アソシエーションを作成したら、エンティティ・オブジェクトとは別に表示および管理できるように、すべてのアソシエーションを別のパッケージに移動します。図4-2では、アソシエーションはサブパッケージ(associations)に移動されているため、「アプリケーション・ナビゲータ」のentitiesパッケージには表示されません。詳細は、4.3.4項「アソシエーションの名前変更および別のパッケージへの移動方法」を参照してください。 |
単一のエンティティ・オブジェクトを作成するには、「新規ギャラリ」から使用可能なエンティティ・オブジェクト作成ウィザードを使用します。
単一のエンティティ・オブジェクトおよびアソシエーションを作成するには:
アプリケーション・ナビゲータで、エンティティ・オブジェクトを作成するプロジェクトを右クリックし、「新規」を選択します。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」を選択してから「エンティティ・オブジェクト」を選択し、「OK」をクリックします。
これがプロジェクトで作成する最初のコンポーネントである場合、「ビジネス・コンポーネント・プロジェクトの初期化」ダイアログが表示され、データベース接続を選択できます。
「ビジネス・コンポーネント・プロジェクトの初期化」ダイアログで、データベース接続を選択するか、「新規」を選択して接続を作成します。「OK」をクリックします。
「名前」ページで、次の操作を実行してエンティティ・オブジェクトを作成します。
エンティティ・オブジェクトが作成されるパッケージ名を入力します。
「参照」(「スキーマ・オブジェクト」フィールドの横)をクリックし、エンティティ・オブジェクトを作成する表を選択します。
または、表を後で作成する場合は、現在使用されていない名前を入力できます。
「スキーマ・オブジェクト」フィールドに表の名前を手動で入力する場合、ウィザードの「属性」ページで、各属性を定義する必要があります。「次へ」をクリックします。
4.2.6項「エンティティ・オブジェクトからのデータベース表の作成方法」で説明するように、この表は手動で作成または生成できます。
目的の表オブジェクトとそれに対応するエンティティ・オブジェクトの名前の操作が完了したら、「終了」をクリックします。
既存の表からエンティティ・オブジェクトを作成する場合、最初に、次の情報を推測するためにデータ・ディクショナリからデータが取得されます。
表の列名に基づくJavaに適したエンティティ属性名(USER_ID→UserIdなど)
基礎となる列のデータ型に基づく各属性のSQLおよびJavaデータ型
各属性の長さと精度
主キーと一意キーの属性
NOT NULL制約に基づく属性の必須フラグ
外部キーの制約に基づく新規エンティティ・オブジェクトとその他のエンティティ間の関連
|
注意: エンティティ・オブジェクトはデータベース行を表しているため、エンティティ行と呼ぶのが自然です。または、エンティティ行は実行時にそのデータベース行のビジネス・ロジックをカプセル化するJavaオブジェクト・インスタンスであるため、エンティティ・インスタンスという、よりオブジェクト指向の呼び方も適しています。このため、これらの2つの用語は同義です。 |
これにより、宣言的設定を表すXMLコンポーネント定義ファイルが作成され、パッケージ名と対応するディレクトリに保存されます。たとえば、Orderという名前のエンティティがgenericbcmodel.entitiesパッケージに含まれる場合、JDeveloperによりそのプロジェクトのソース・パスにgenericbcmodel/entities/Order.xmlというXMLファイルが作成されます。このXMLファイルには、表の名前、各エンティティ属性の名前とデータ型、および各属性の列名が含まれます。
概要エディタでオブジェクトを開き、「ソース」タブをクリックすると、エンティティ・オブジェクトのXML記述内容を検証できます。
|
注意: IDEレベルのビジネス・コンポーネントのJava生成設定で指定されている場合、オプションのカスタム・エンティティ・オブジェクト・クラス(OrderImpl.javaなど)もウィザードで生成される場合があります。 |
エンティティ・オブジェクト以外に、エンティティ・オブジェクト間の関連に関する情報を取得する名前付きアソシエーション・コンポーネントも生成されます。たとえば、図4-3のデータベース・ダイアグラムを見ると、外部キー制約名をJavaに適した名前に変換してAssoc接尾辞を付けることにより、OrderItemsProductsFkAssocなどのデフォルトのアソシエーション名が導出されることを確認できます。作成されたアソシエーションごとに、適切なXMLコンポーネント定義ファイルが作成され、パッケージ名と対応するディレクトリに保存されます。
デフォルトでは、外部キーからリバース・エンジニアリングされたアソシエーションは、エンティティと同じパッケージ内に作成されます。たとえば、fodemo.storefront.entitiesパッケージ内にあるエンティティへのアソシエーションOrderItemsProductsFkAssocに対しては、JDeveloperにより./fodemo/storefront/entities/OrderItemsProductsFkAssoc.xmlという名前のアソシエーションXMLファイルが作成されます。
表に主キー制約がない場合、JDeveloperは、エンティティ・オブジェクトの主キーを推測できません。すべてのエンティティ・オブジェクトには少なくとも1つの属性が主キーとしてマークされている必要があるため、ウィザードでは、RowIDという名前の属性が作成され、データベースのROWID値がこのエンティティの主キーとして使用されます。必要な場合、後でエンティティ・オブジェクトを編集し、別の属性を主キーとしてマークし、RowID属性を削除できます。エンティティ・オブジェクト作成ウィザードを使用する場合、その他の属性を主キーとして設定していないと、RowIDを主キーとして使用するよう求められます。
「表からのビジネス・コンポーネント」ウィザードまたはエンティティ・オブジェクトの作成ウィザードを使用してエンティティ・オブジェクトを作成する場合、オブジェクトは基礎となる表、シノニム、またはビューを表すことができます。フレームワークは、データ・ディクショナリ内のデータベースの主キーおよび外部キー制約を調べることにより、主キーおよび関連するアソシエーションを推測できます。
ただし、選択したスキーマ・オブジェクトがデータベース・ビューである場合、データベース・ビューにはデータベース制約がないため、主キーもアソシエーションも推測できません。この場合、「表からのビジネス・コンポーネント」ウィザードを使用すると、主キーはRowIDにデフォルト設定されます。エンティティ・オブジェクト作成ウィザードを使用する場合、少なくとも1つの属性を主キーとしてマークすることにより、主キーを手動で指定する必要があります。詳細は、4.2.3.2項「表に主キーがないときに行われる処理」を参照してください。
選択したスキーマ・オブジェクトがシノニムである場合、結果には2種類あります。シノニムが表のシノニムである場合、ウィザードおよびエディタは、表を指定した場合と同じように動作します。かわりに、シノニムがデータベース・ビューを参照している場合、ウィザードおよびエディタは、ビューを指定した場合と同じように動作します。
新しいエンティティ・オブジェクトまたはアソシエーションを作成した後、概要エディタでその設定を編集できます。エディタを起動するには、「アプリケーション・ナビゲータ」のエンティティ・オブジェクトまたはアソシエーションのポップアップ・メニューで「開く」を選択するか、オブジェクトをダブルクリックします。エディタの別のタブをクリックすることにより、オブジェクトを定義する設定や、その実行時の動作を制御する設定を調整できます。
エンティティ・オブジェクトに基づいてデータベース表を作成するには、エンティティ・オブジェクトが含まれるアプリケーション・ナビゲータでパッケージを右クリックし、ポップアップ・メニューから「データベース・オブジェクトの作成」を選択します。ダイアログが表示され、表の作成元のエンティティを選択できます。このツールを使用して、作成したエンティティ・オブジェクトの表を最初から生成することも、既存の表をドロップして再作成することもできます。
|
注意: この機能では、後で実行するDDLスクリプトは生成されません。データベースに対して操作が直接実行され、既存の表がドロップされます。作業に進む前に、この処理を実行するかどうかを確認するダイアログが表示されます。既存の表に基づくエンティティの場合、慎重に作業してください。 |
アソシエーションの概要エディタの「アソシエーション・プロパティ」ページにある「データベース・キー制約の使用」チェック・ボックスにより、エンティティ・オブジェクトの表の作成時に、関連する外部キー制約を生成するかどうかを制御します。このオプションを選択しても、実行時には影響しません。
すでにエンティティ・オブジェクトを作成した表も、自分で(またはDBAが)変更する必要がある場合があります。基礎となる表に属性が追加されても既存のエンティティに混乱が生じることはありませんが、Java EEアプリケーションで表内の新しい列にアクセスするには、エンティティ・オブジェクトをデータベース表と同期化する必要があります。
たとえば、SQL*Plusコマンド・プロンプトで次を実行し、新しいSECURITY_QUESTION列をPERSONS表に追加したとします。
ALTER TABLE PERSONS ADD (security_question VARCHAR2(60));
同期化機能を使用すると、エンティティ・オブジェクトに新規列を属性として追加できます。
データベース表の変更とエンティティを同期化するには:
「アプリケーション・ナビゲータ」で、目的のエンティティ・オブジェクトを右クリックし、「データベースとの同期化」を選択します。
「データベースとの同期化」ダイアログに、ビジネス・ロジック層とデータベースの同期化に実行可能なアクションのリストが表示されます。
実行するアクションを選択します。
選択した項目を同期化するには、リストからアクションを1つ以上選択し、「同期化」をクリックします。
リスト内のすべてのアクションを実行するには、「すべて同期化」をクリックします。
アクション・リストをテキスト・ファイルに保存するには、「保存」をクリックします。この機能では、変更内容を追跡できます。
終了したら、「OK」をクリックして、ダイアログを閉じます。
同期化機能では、ドロップされた列は処理されません。エンティティ・オブジェクトの作成後に基礎となるデータベースから列がドロップされた場合は、対応する属性をエンティティ・オブジェクトから削除できます。属性がアプリケーションの他の部分で使用される場合は、それらの使用方法も削除する必要があります。
エンティティ属性を削除するには:
「アプリケーション・ナビゲータ」で、エンティティをダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックします。
「属性」ページで属性を右クリックし、「安全に削除」を選択します。
他の使用方法がある場合は、「属性の削除」ダイアログに「使用方法が見つかりました。」のメッセージが表示されます。
使用方法が見つかった場合は、「使用方法の表示」をクリックします。
「ログ」ウィンドウに、属性のすべての使用方法が表示されます。
「ログ」ウィンドウのリストを確認し、エンティティ属性の使用方法をすべて削除します。
特定の時点に関するデータセットを表示する場合は、有効日が指定された表が使用されます。有効日が指定された表は、次のような問合せを処理するHRMSやPayrollなどのアプリケーションで広く使用されています。
2005年8月31日現在の従業員への課税率はどの程度か。
2004年10月現在の従業員の給料はどの程度か。
この2つのいずれかについて、従業員のデータがそれ以降変更されている場合があります。
有効日が指定されたエンティティ・タイプと日付が指定されたエンティティ・タイプの主な違いは、日付が指定されたエンティティ・タイプでは、更新および削除中に行が分割されないことです。
|
注意: マスター/ディテール関係の両側で有効日を使用する場合は注意が必要です。子オブジェクトは親オブジェクトに対するイベントを呼び出すことができ、有効日が指定されたエンティティ・オブジェクトは更新および削除操作中に行が分割されるため、親と子が同じトランザクション中に更新されると、子オブジェクトは間違った親オブジェクトに対するイベントを呼び出す可能性があります。有効日が指定された子から有効日が指定された親に対して呼び出されるようなビジネス・イベントを構成しないでください。ビジネス・イベントの詳細は、4.11項「ビジネス・イベントの作成」を参照してください。 |
有効日が指定されたエンティティ・オブジェクトを作成する場合は、エンティティを有効日指定として識別し、開始日と終了日を表すエンティティの属性を指定します。開始日と終了日の属性はDate型にする必要があります。
また、有効日が指定されたエンティティの順序を表す属性や、順序のフラグを表す属性を指定することもできます。これらの属性では、1日に行われた複数の変更を追跡できます。
有効日が指定されたエンティティ・オブジェクトを作成するには
「アプリケーション・ナビゲータ」で、有効日を指定するエンティティをダブルクリックします。
「プロパティ・インスペクタ」で、「タイプ」カテゴリを展開します。
必要に応じて、「ビュー」メニューから「プロパティ・インスペクタ」を選択して、プロパティ・インスペクタを表示します。
「プロパティ・インスペクタ」に「タイプ」カテゴリが表示されていない場合は、概要エディタの「一般」タブをクリックし、適切なフォーカスを設定します。
「有効日タイプ」プロパティのポップアップ・メニューから、「編集」を選択します。
ポップアップ・メニューを表示するには、プロパティ・フィールドの横の下矢印をクリックします。
「プロパティの編集」ダイアログで、次の設定を指定します。
「有効日タイプ」で、EffectiveDatedを選択します。
「開始日属性」で、開始日に対応する属性を選択します。
「終了日属性」で、終了日に対応する属性を選択します。
必要に応じて、1日に行われた複数の変更の追跡を可能にする属性を指定することもできます。
「有効日シーケンス」で、変更の順序を格納する属性を選択します。
「有効日シーケンス・フラグ」で、順序内の最新の変更を示すフラグを格納する属性を選択します。
「有効日シーケンス」属性と「有効日シーケンス・フラグ」属性を指定しない場合、有効日指定のデフォルトの粒度は1日になります。このため、1日に複数の変更を行うことはできなくなります。1日にエンティティを複数回更新しようとすると、例外がスローされます。これらの2つの属性を指定すると、フレームワークには、1日に行われた複数の変更の追跡に必要な値が挿入されて更新されます。
「OK」をクリックします。
|
注意: プロパティ・インスペクタを使用して、該当の属性に開始日と終了日の属性を指定することもできます。この場合は、概要エディタで該当の属性を選択し、「プロパティ・インスペクタ」でIsEffectiveStartDateプロパティまたはIsEffectiveEndDateプロパティをtrueに設定します。 |
有効日が指定されたエンティティ・オブジェクトを作成すると、SysEffectiveDateと呼ばれる一時属性が作成され、行の有効日が格納されます。通常は、挿入、更新および削除の操作によって一時属性が変更されますが、ADFビジネス・コンポーネント・フレームワークでは、「有効日開始」と「有効日終了」で適切な値を決定します。
例4-1は、有効日が指定されたエンティティを作成したときに生成されるサンプルのXMLエントリの一部を示しています。有効日が指定されたオブジェクトの使用方法の詳細は、5.4項「有効日付範囲を使用したビュー・オブジェクト行の制限」を参照してください。
例4-1 有効日が指定されたエンティティのXMLエントリ
// In the effective dated entity
<Entity
...
EffectiveDateType="EffectiveDated">
// In the attribute identified as the start date
<Attribute
...
IsEffectiveStartDate="true">
// In the attribute identified as the end date
<Attribute
...
IsEffectiveEndDate="true">
// The SysEffectiveDate transient attribute
<Attribute
Name="SysEffectiveDate"
IsQueriable="false"
IsPersistent="false"
ColumnName="$none$"
Type="oracle.jbo.domain.Date"
ColumnType="$none$"
SQLType="DATE"/>
「表からのビジネス・コンポーネント」ウィザードを使用すると、同時に多くのビジネス・コンポーネントを簡単に作成できます。とはいえ、単にこの処理が可能だという理由でこのウィザードを使用して、データベース・スキーマ内のすべての表についてエンティティ・オブジェクトを即座に作成する必要はありません。アプリケーションですべての表が必要な場合は、この方法が適しています。ただし、このウィザードは必要であればいつでも使用できるため、アプリケーションに必要なことがわかっている表についてエンティティ・オブジェクトを作成することをお薦めします。
9.4項「ネストされたアプリケーション・モジュールの定義」では、ビジネス・サービスのユース・ケース駆動型設計方法について説明されており、アプリケーションのビジネス・ロジックのニーズをサポートするために必要なエンティティ・オブジェクトを理解する上で役立ちます。エンティティ・オブジェクトは、必要に応じて後でいつでも追加できます。
データベース表に外部キー制約が定義されていない場合、作成されたエンティティ・オブジェクト間のアソシエーションはJDeveloperにより推測されません。一部のADFビジネス・コンポーネント・ランタイム機能はエンティティ・アソシエーションが存在しているかどうかに依存するため、外部キーが存在しない場合は、エンティティ・アソシエーションを手動で作成することをお薦めします。
アソシエーションを作成するには、「新規ギャラリ」から使用できる新規アソシエーション作成ウィザードを使用します。
アソシエーションを作成するには、次のようにします。
アプリケーション・ナビゲータで、アソシエーションを作成するプロジェクトを右クリックし、「新規」をクリックします。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」を選択したら、「アソシエーション」を選択し、「OK」をクリックします。
「名前」ページで、次の操作を実行してエンティティ・オブジェクトを作成します。
アソシエーションが作成されるパッケージ名を入力します。
アソシエーション・コンポーネントの名前を入力します。
「次へ」をクリックします。
「エンティティ・オブジェクト」ページで、ソースおよびリンク先のエンティティ属性を選択します。
アソシエーションに含まれ、マスターとして機能するエンティティ・オブジェクトの1つからソース属性を選択します。
アソシエーションに含まれるその他のエンティティ・オブジェクトから、対応するリンク属性を選択します。
たとえば、図4-4では、OrderEOエンティティ・オブジェクトからソース・エンティティ属性としてOrderId属性が選択されています。OrderItemEOの各行には、これらの行を特定のOrderEO行に関連付けるオーダーIDが含まれるため、OrderItemEOエンティティ・オブジェクトでこのOrderId外部キー属性をリンク先属性として選択します。
「追加」をクリックし、対応する属性ペアを、下にあるソース属性とリンク先属性のペアの表に追加します。
デフォルトでは、ソース属性とリンク先属性の両方で「バインド済」チェックボックスが選択されています。このチェックボックスでは、(選択する側に応じて)ソース・エンティティからターゲット・エンティティ、またはターゲット・エンティティからソース・エンティティに移動する際に内部で作成されるアソシエーションSQL文に値をバインドするかどうかを指定できます。
値が定数であるためにエンティティを取得するためのアソシエーションSQL文に含めない一時エンティティ属性である関連内の属性のチェック・ボックスは、通常は選択を解除します。
アソシエーションを定義するために複数の属性ペアが必要な場合、これらのステップを繰り返し、ソース/ターゲット属性ペアをさらに追加できます。
最後に、「カーディナリティ」ドロップダウンに表示されているアソシエーションのカーディナリティが正しいことを確認します。デフォルトは1対多関係です。「次へ」をクリックします。
たとえば、OrderEO行と対応するOrderItemEO行間の関連は1対多であるため、デフォルト設定のままでかまいません。
「アソシエーションSQL」ページで、ソース・エンティティ・オブジェクトの特定のインスタンスに関連するリンク先エンティティ・オブジェクトにアクセスするために実行時に使用するアソシエーションSQL述語をプレビューできます。
一方向関連を表すアソシエーションを作成する場合は、「アソシエーション・プロパティ」ページで、ソース・エンティティ・オブジェクトまたはリンク先エンティティ・オブジェクトの「アクセッサの公開」チェック・ボックスの選択を解除します。ビジネス検証ロジックを作成する場合、双方向関連ナビゲーションの方が便利なため、通常これらのデフォルトのチェック・ボックス設定のままにしておきます。
たとえば、図4-5は、どちら側のエンティティ・オブジェクトも必要に応じて反対側の関連エンティティ行にアクセスできる双方向関係を表しています。つまり、この例では、OrderEOエンティティ・オブジェクトのインスタンスを操作している場合、関連するOrderItemEO行のコレクションに簡単にアクセスできます。また、OrderItemEOエンティティ・オブジェクトのインスタンスを使用して、これが属するOrderにも簡単にアクセスできます。
目的のアソシエーションを定義したら、「終了」をクリックします。
アソシエーションを作成すると、適切なXMLコンポーネント定義ファイルが作成され、パッケージ名と対応するディレクトリに保存されます。たとえば、oracle.fodemo.storefront.entities.associationsサブパッケージ内にOrderItemsOrdersFkAssocという名前のアソシエーションを作成した場合、アソシエーションXMLファイルがOrderItemsOrdersFkAssoc.xmlという名前で./oracle/fodemo/storefront/entities/associationsディレクトリに作成されます。実行時には、エンティティ・オブジェクトはこのアソシエーション情報を使用して、一連の関連エンティティの操作を自動化します。
「アソシエーション・プロパティ」ページのアクセッサ名のデフォルト設定について検討し、これらの名前をより直感的なものに変更した方が適切かどうかを決定する必要があります。このデフォルト設定により、実行時に関連の反対側のエンティティにプログラム的にアクセスするときに使用するアクセッサ属性の名前が定義されます。デフォルトでは、これらのアクセッサ名は、反対側のエンティティ・オブジェクトの名前になります。エンティティのアクセッサ名は、エンティティ・オブジェクト属性とその他のアクセッサ間で一意である必要があるため、1つのエンティティが複数の方法で別のエンティティに関連付けられている場合、デフォルトのアクセッサ名は、名前を一意にするために数値接尾辞を使用して変更されます。
既存のアソシエーションでは、「アソシエーション・プロパティ」ダイアログを使用してアクセッサの名前を変更できます。
アソシエーション内のエンティティ・アクセッサの名前を変更するには:
「アプリケーション・ナビゲータ」で、アソシエーションをダブルクリックします。
概要エディタで、「関連」ナビゲーション・タブをクリックします。
「関連」ページで、「アクセッサ」カテゴリを展開し、「編集」アイコンをクリックします。
「アソシエーション・プロパティ」ダイアログに、アソシエーションのアクセッサの現在の設定が表示されます。
必要に応じて名前を変更し、「OK」をクリックして変更内容を適用し、ダイアログを閉じます。
アソシエーションは、通常はプロジェクトの最初に構成し、それ以降はそれほど頻繁に変更しないコンポーネントであるため、アソシエーションを別のパッケージに移動し、エンティティ・オブジェクトを見やすくできます。コンポーネントの名前変更と別のパッケージへの移動は両方とも、JDeveloperのリファクタ機能を使用して直接実行します。
別のパッケージにビジネス・コンポーネントのセットを移動するには:
アプリケーション・ナビゲータで、移動するコンポーネントを選択します。
選択したコンポーネントを右クリックし、「リファクタ」→「移動」を選択します。
「ビジネス・コンポーネントを移動」ダイアログで、コンポーネントを移動するパッケージの名前を入力するか、「参照」をクリックしてパッケージに移動して選択します。
「OK」をクリックして変更内容を適用し、ダイアログを閉じます。
コンポーネントの名前を変更するには:
「アプリケーション・ナビゲータ」で、名前を変更するコンポーネントを右クリックし、「リファクタ」→「名前の変更」を選択します。
「名前の変更」ダイアログで、コンポーネントの新しい名前を入力し、「OK」をクリックします。
ADFビジネス・コンポーネントをリファクタする場合、コンポーネントに関連するXMLファイルおよびJavaファイルがJDeveloperにより移動されるとともに、これらを参照するその他のコンポーネントが更新されます。
図4-6は、すべてのアソシエーションの名前を変更し、これらをoracle.fodemo.storefront.associationsサブパッケージに移動した後のアプリケーション・ナビゲータの様子を示しています。任意のパッケージ名を選択してアソシエーションをリファクタすることにより、サブパッケージを使用してアソシエーションとエンティティとの論理的な関連を維持しながらアソシエーションのパッケージを閉じることができるため、アプリケーション・ナビゲータに表示するファイルをより効率的に管理できます。
カスタム・ビュー・オブジェクトをエンティティ・アソシエーションのリンク元またはリンク先(あるいは両方)に関連付けることができます。
コード内でエンティティ・アソシエーションをトラバースするときに、エンティティがキャッシュにない場合は、ADFビジネス・コンポーネント・フレームワークによって問合せが実行され、エンティティ(複数可)がキャッシュに取り込まれます。デフォルトでは、エンティティをキャッシュに取り込むために実行される問合せは、主キーによる検索の問合せで、基礎となる表からすべての永続エンティティ属性の値を選択します。アプリケーションでプログラム的なエンティティ・アソシエーションのトラバースが多く実行される場合、すべての属性を取得することは、無理なユースケースになる場合があります。
エンティティ・アソシエーションでは、カスタムのエンティティ・ベースのビュー・オブジェクトをアソシエーション内のソース・エンティティまたは関連先エンティティ(あるいは両方)に関連付けることができます。指定するエンティティ・ベースのビュー・オブジェクトのプライマリ・エンティティ・オブジェクトの慣用名は、それを使用するアソシエーションの端のエンティティ・タイプに一致する必要があります。
カスタム・ビュー・オブジェクトの問合せには少ない列を含めることが可能で、ORDER BY句を含めることができるため、カスタム・ビュー・オブジェクトを使用する方が便利な場合があります。これにより、アソシエーションのトラバースによりエンティティがキャッシュに取り込まれる際に取得されるデータの量だけでなく、関連するエンティティのコレクションの順序も制御できます。
カスタム・ビュー・オブジェクトの作成の詳細は、39.8.2項「プログラムでエンティティ・ベースのビュー・オブジェクトを作成する方法」を参照してください。
アソシエーションは、Orderが参照するPersonや、Orderに含まれるOrderItemなどのエンティティ間の関連を表しています。アソシエーションを作成する場合、表現可能な関連の種類や様々なオプションについて理解していると役に立ちます。
エンティティ・オブジェクト間の関連を使用して、次のようなソース・エンティティの状態に応じて2つのスタイルの関連を表現できます。
関連先エンティティを参照している
ネストされた論理的部分として関連先エンティティが含まれる
図4-7は、この2つのスタイルの関連を表すアプリケーション・ビジネス・レイヤーを示しています。たとえば、OrderEOエントリはPersonEOを参照しています。これらの関連は、第一種のアソシエーションを示し、PersonEOまたはOrderEOエンティティ・オブジェクトは互いに独立して存在することができます。また、Orderを削除しても、これが参照していたPersonがカスケード削除されることはありません。
一方、OrderEOと関連するOrderItemEOディテールのコレクション間の関係は、単純な参照よりも強力です。OrderItemEOエントリは、OrderEO全体の論理部分を構成しています。つまり、OrderEOはOrderItemEOエントリで構成されています。OrderItemEOエンティティ行にとって、OrderEOから独立して存在することは意味をなさず、(削除が許可されていて)OrderEOを削除する場合には、その構成部分もすべて削除する必要があります。このタイプの論理関係は、コンポジットと呼ばれる第二種のアソシエーションを示します。図4-7のUMLダイアグラムでは、アソシエーションで他方を構成する側に黒い菱形を使用して、より強力なコンポジット関連を示しています。
「表からのビジネス・コンポーネント」ウィザードでは、ON DELETE CASCADEオプションを持つ外部キーに対してデフォルトでコンポジット・アソシエーションが作成されます。アソシエーション作成ウィザードまたはアソシエーションの概要エディタを使用すると、アソシエーションをコンポジット・アソシエーションとして指定できます。「アソシエーションの作成」ウィザードの「アソシエーション・プロパティ」ページ、または概要エディタの「関連」ページで、「コンポジット・アソシエーション」チェック・ボックスを選択します。
|
注意: コンポジット・アソシエーションは、一時属性をベースに作成できません。 |
コンポジット・アソシエーションがある場合、エンティティ・オブジェクトには実行時に別の動作が追加されます。動作の制御設定については、4.10.13項「コンポジット動作の構成方法」を参照してください。
ビジネス・ドメイン・オブジェクトのレイヤーはチームにとって再使用可能な主要資産となるため、多くの場合、UMLモデルを使用して視覚化すると使いやすくなります。JDeveloperでは、自分やチームのメンバーが参照用として使用できるビジネス・ドメイン・レイヤーのダイアグラムを簡単に作成できるようサポートされています。
ビジネス・コンポーネントのUMLダイアグラムは、エンティティ・オブジェクトをダイアグラムにドロップしたときを示す静的な図のみではありません。むしろ、UMLダイアグラムは、現在のコンポーネント定義をUMLベースでレンダリングした図であるため、常に現在の状況を示しています。さらに、UMLダイアグラムは、視覚的なサポートとナビゲーションを提供するツールであるとともに、編集用のツールでもあります。ダイアグラムでエンティティ・オブジェクトについて概要エディタを開くには、目的のオブジェクトを右クリックしてポップアップ・メニューから「プロパティ」を選択するか、目的のオブジェクトをダブルクリックします。また、エンティティおよびエンティティ属性の名前変更や属性の追加または削除など、エンティティ・オブジェクトの編集タスクをダイアグラム上で直接実行することもできます。
エンティティ・オブジェクトのダイアグラムを作成するには、「新規ギャラリ」から使用可能な「ビジネス・コンポーネント・ダイアグラムの作成」ダイアログを使用できます。
既存のエンティティ・オブジェクトをモデル化するビジネス・コンポーネント・ダイアグラムを作成する手順
アプリケーション・ナビゲータで、エンティティ・ダイアグラムを作成するプロジェクトを右クリックし、「新規」をクリックします。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」を選択したら、「ビジネス・コンポーネント・ダイアグラム」を選択し、「OK」をクリックします。
このダイアログで、次の操作を実行してダイアグラムを作成します。
ダイアグラムの名前を入力します(Business Domain Objectsなど)。
ダイアグラムが作成されるパッケージ名を入力します。たとえば、myproject.model.designなどのサブパッケージ内にダイアグラムを作成します。
「OK」をクリックします。
既存のエンティティ・オブジェクトをダイアグラムに追加するには、アプリケーション・ナビゲータでこれらのオブジェクトを選択し、ダイアグラムにドロップします。
ダイアグラムを作成したら、プロパティ・インスペクタを使用してダイアグラムのビジュアル・プロパティを調整できます。たとえば、次の操作が可能です。
パッケージ名の表示と非表示の切替え
フォントの変更
グリッドおよび改ページの切替え
アソシエーション名の表示(表示しないと曖昧になる場合)
ダイアグラム上でポップアップ・メニューから「ダイアグラムの公開」を選択すると、ダイアグラムのイメージをPNG、JPG、SVGまたは圧縮されたSVG書式で作成することもできます。
図4-8は、ビジネス・ドメイン・レイヤーの様々なエンティティ・オブジェクトをモデル化したサンプル・ダイアグラムを示しています。
ビジネス・コンポーネント・ダイアグラムを作成すると、ダイアグラムが格納されているパッケージ名と一致するプロジェクトのモデル・パスのサブディレクトリに、ダイアグラムを示すXMLファイル*.oxd_bc4jが作成されます。
デフォルトでは、アプリケーション・ナビゲータによってプロジェクト・コンテンツ・パスの表示が統一され、ソース・パスのADFコンポーネントおよびJavaファイルがプロジェクト・モデル・パスのUMLモデル・アーティファクトと同じパッケージ・ツリーに表示されます。ただし、図4-9のように、アプリケーション・ナビゲータの「ナビゲータの表示オプション」ツールバー・ボタンを使用すると、必要に応じて、プロジェクト・コンテンツ・パスのルート・ディレクトリを個別に表示できます。
エンティティ・オブジェクトなどのビジネス・コンポーネントをUMLダイアグラムに含めると、例4-2のように、コンポーネントのXMLコンポーネント・ディスクリプタの<Data>セクションにメタデータが追加されます。この追加情報が使用されるのは設計時のみです。
例4-2 エンティティ・オブジェクトXMLディスクリプタに追加されたUMLメタデータ
<Entity Name="OrderEO" ... >
<Data>
<Property Name ="COMPLETE_LIBRARY" Value ="FALSE" />
<Property Name ="ID"
Value ="ff16fca0-0109-1000-80f2-8d9081ce706f::::EntityObject" />
<Property Name ="IS_ABSTRACT" Value ="FALSE" />
<Property Name ="IS_ACTIVE" Value ="FALSE" />
<Property Name ="IS_LEAF" Value ="FALSE" />
<Property Name ="IS_ROOT" Value ="FALSE" />
<Property Name ="VISIBILITY" Value ="PUBLIC" />
</Data>
:
</Entity>
プロパティ・セットとはプロパティの名前付きコレクションで、各プロパティが名前/値のペアとして定義されています。プロパティ・セットは、プロパティをグループ化し、それらを他のADFビジネス・コンポーネント・オブジェクトから参照するための便利なメカニズムです。プロパティ・セット内で定義されたプロパティは、翻訳可能に構成でき、そのようなケースでは、翻訳されたプロパティはプロパティ・セットが所有するメッセージ・バンドル・ファイルに格納されます。
プロパティ・セットは、コントロール・ヒントやエラー・メッセージなど、様々な機能に使用できます。各プロパティ・セットには、コントロール・ヒントなどのカスタム・プロパティを含めることができ、それらを別のオブジェクトの複数の属性に関連付けることもできます。
|
注意: 翻訳可能なコンテンツを含むプロパティ・セットを定義する場合は注意が必要です。異なるコンテンツでは、共通の用語を過度に使用しないようにしてください。たとえば、ある言語では「Name」という用語をオブジェクトと個人の両方に適用できる場合でも、ターゲット言語では2つの異なる用語に翻訳される場合があります。ソース言語では複数のコンテンツで同じ用語にできる場合でも、コンテンツごとに区別できる用語を使用するようにしてください。 |
プロパティ・セットは、エンティティ・オブジェクトとその属性、ビュー・オブジェクトとその属性、およびアプリケーション・モジュールで使用できます。
プロパティ・セットを定義するには、ダイアログを使用して新規のプロパティ・セットを作成し、プロパティ・インスペクタを使用してプロパティを指定します。
プロパティ・セットを定義するには:
「アプリケーション・ナビゲータ」で、プロパティ・セットを作成するプロジェクトを右クリックし、「新規」を選択します。
「新規ギャラリ」で、「ビジネス層」を展開し、「ADFビジネス・コンポーネント」を選択してから「プロパティ・セット」を選択し、「OK」をクリックします。
「プロパティ・セットの作成」ダイアログで、プロパティ・セットの名前および場所を入力し、「OK」をクリックします。
「ビュー」メニューから「プロパティ・インスペクタ」を選択します。
「プロパティ・インスペクタ」で、プロパティ・セットに対してプロパティを定義します。
プロパティ・セットを作成すると、プロパティ・セットをエンティティ・オブジェクトやエンティティ属性に適用できるだけでなく、定義されたプロパティを使用(必要に応じてオーバーライド)することもできます。
エンティティ・オブジェクトまたはビュー・オブジェクトにプロパティ・セットを適用するには:
「アプリケーション・ナビゲータ」で、目的のオブジェクト(エンティティ・オブジェクトまたはビュー・オブジェクト)をダブルクリックします。
概要エディタの「一般」ナビゲーション・タブをクリックし、「プロパティ・セット」行の横の「編集」アイコンをクリックします。
適切なプロパティ・セットを選択し、「OK」をクリックします。
プロパティ・セットを属性に適用するには:
「アプリケーション・ナビゲータ」で、目的のオブジェクト(エンティティ・オブジェクトまたはビュー・オブジェクト)をダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックし、編集する属性をダブルクリックします。
「属性の編集」ダイアログで、第1ノードをクリックして属性の一般プロパティを表示します。
ビュー・オブジェクトの場合は、「ビュー属性」ノードです。エンティティ・オブジェクトの場合は、「エンティティ属性」ノードです。
「プロパティ・セット」ドロップダウン・リストで、適切なプロパティ・セットを選択し、「OK」をクリックします。
前のバージョンのADFビジネス・コンポーネントになじみのあるユーザーであれば、すでにコントロール・ヒントを使用した経験がある場合があります。コントロール・ヒントを使用すると、エンティティ・オブジェクト属性のラベル・テキスト、ツールチップおよびフォーマット・マスクのヒントを定義できます。ビジネス・ドメイン・レイヤーで定義するUIヒントは、エンティティ・ベースのビュー・オブジェクトによって継承されます。また、ビュー・オブジェクトやアプリケーション・モジュールでも同様にコントロール・ヒントを追加設定できます。
属性のコントロール・ヒントをエンティティ・オブジェクトに追加するには、概要エディタを使用します。
属性のコントロール・ヒントをエンティティ・オブジェクトに追加するには:
アプリケーション・ナビゲータで、目的のエンティティ・オブジェクトをダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックし、編集する属性をダブルクリックします。
「属性の編集」ダイアログで、「コントロール・ヒント」ノードをクリックし、属性のコントロール・ヒントを表示します。
必要に応じてコントロール・ヒントを指定し、「OK」をクリックします。
例として、図4-11は、PaymentOptionEOエンティティ・オブジェクトの属性ExpireDateに定義されたコントロール・ヒントを示しています。定義されるヒントは、次のとおりです。
フォーマットの種類: Simple Date
「フォーマット」マスク: yyyy-MM-dd
|
注意: Javaで定義される数値および日付のフォーマット・マスクの標準セットは、OracleデータベースのSQLおよびPL/SQL言語によって使用されるものとは異なります。詳細は、java.text.DecimalFormatおよびjava.text.SimpleDateFormatクラスのJavadocを参照してください。 |
エンティティ・オブジェクトの属性のコントロール・ヒントを定義すると、これらを格納するリソース・バンドル・ファイルが作成されます。定義したヒントは、関連付けられたビュー・クライアントにおいて生成されたフォームおよび表によって使用できます。ファイルのタイプとその粒度は、「プロジェクト・プロパティ」ダイアログの「リソース・バンドル」オプションで指定します。詳細は、4.7項「リソース・バンドルの使用」を参照してください。
(「属性の編集」ダイアログで)属性(たとえば、Simple Date)の「フォーマット・タイプ」コントロール・ヒントを設定する場合、この属性にフォーマット・マスクも指定して、UIでの値の表示方法をカスタマイズできます。使用するマスクが「フォーマット」ドロップダウン・リストに表示されない場合は、フィールドに直接入力できます。
すべてのフォーマッタがフォーマット・マスクを必要とするわけではありません。フォーマット・マスクは、フォーマッタ・タイプによって必要とされる場合にのみ指定が必要です。たとえば、日付フォーマッタにはフォーマット・マスクが必要ですが、通貨フォーマッタには必要ありません。実際、通貨フォーマッタではフォーマット・マスクはサポートされていません。
使用できるマスク要素は、関連するJavaフォーマット・クラスで定義されています。Simple Dateフォーマット・タイプのマスク要素の詳細は、Javadocのjava.text.SimpleDateFormatを参照してください。Numberフォーマット・タイプのマスク要素の詳細は、Javadocのjava.text.DecimalFormatを参照してください。
今後繰り返し使用するフォーマット・マスクがある場合は、「属性の編集」ダイアログの「フォーマット」ドロップダウン・リストで利用できるように、formatinfo.xmlファイルに追加できます。このファイルのエントリでは、ドメイン・クラスのフォーマット・マスクおよびフォーマッタ・クラスを定義します。例4-3は、java.util.Dateドメインのフォーマット定義を示しています。
|
注意: formatinfo.xmlファイルは、JDeveloperシステム・ディレクトリのBC4Jサブディレクトリにあります(たとえば、C:\Documents and Settings\username\Application Data\JDeveloper\system##\o.BC4J\formatinfo.xmlです)。 |
例4-3 formatinfo.xmlのjava.util.Dateのフォーマット定義
<?xml version="1.0"?><FORMATTERS>
. . .
<DOMAIN CLASS="java.util.Date">
<FORMATTER name="Simple Date" class="oracle.jbo.format.DefaultDateFormatter">
<FORMAT text="yyyy-MM-dd" />
<FORMAT text="EEE, MMM d, ''yy" />
<FORMAT text="dd-MM-yy" />
<FORMAT text="dd-MMM-yyyy" />
<FORMAT text="dd/MMM/yyyy" />
</FORMATTER>
</DOMAIN>
. . .
</FORMATTERS>
フォーマット・マスクの定義は、フォーマッタおよびドメイン・クラスに属し、「属性の編集」ダイアログに表示されるマスクのテキスト指定が含まれています。特定のタイプの属性(DOMAIN CLASS)にフォーマット・タイプ(FORMATTER name)を指定すると、「フォーマット」ドロップダウン・リストにマスク(FORMAT text)が表示されます。
コントロール・ヒントで使用するために、フォーマッタをドメインにマッピングする場合、oracle.jbo.formatパッケージで提供されているデフォルト・フォーマッタの1つを修正するか、oracle.jbo.format.Formatterクラスを拡張して新しいフォーマッタ・クラスを作成できます。JDeveloperに用意されているデフォルトのフォーマッタは、java.textパッケージで提供されているフォーマッタを集約したものです。
フォーマッタをマッピングする上で新規のドメインを作成する必要はありません。ビジネス・コンポーネント・プロジェクトに、フォーマッタと同じデータ型のドメインが含まれている場合は、既存のドメインを使用できます。
新規フォーマット・マスクを定義するには:
テキスト・エディタでformatinfo.xmlファイルを開きます。
フォーマット・マスクを追加するドメイン・クラスとフォーマッタ名を探します。
FORMATTER要素内に新しいFORMATエントリを挿入します。
フォーマット・マスクを定義したら、「属性の編集」ダイアログの「フォーマット」ドロップダウン・リストから新しいフォーマット・マスクを選択できます。
|
注意: フォーマット・マスクの新しいドメインを作成する場合は、フォーマッタのXML定義に、DOMAIN CLASS(新規または既存のもの)、FORMATTER(名前とクラスを含む)、およびフォーマッタ・クラスで指定するFORMAT定義のリストを含める必要があります。 |
翻訳可能な文字列(バリデータ・エラー・メッセージや、エンティティ・オブジェクトまたはビュー・オブジェクトの属性コントロール・ヒントなど)を定義する場合、デフォルトでは、プロジェクト・レベルのリソース・バンドル・ファイルが作成され、そこに翻訳可能文字列が格納されます。たとえば、StoreFrontプロジェクトでエンティティ・オブジェクトのコントロール・ヒントを定義すると、パッケージには、StoreFrontBundle.xxxという名前のメッセージ・バンドル・ファイルが作成されます。定義したヒントは、関連付けられたビュー・クライアントにおいて生成されたフォームおよび表によって使用できます。
JDeveloperで使用されるリソース・バンドルのオプションは、「プロジェクト・プロパティ」ダイアログの「リソース・バンドル」ページのオプションで指定します。このオプションは、デフォルトで「プロパティ・バンドル」に設定され、.propertiesファイルが生成されます。このオプションおよびその他のリソース・バンドル・オプションの詳細は、4.7.1項「メッセージ・バンドル・オプションの設定方法」を参照してください。
アプリケーション・ナビゲータでオブジェクトを選択し、「構造」ウィンドウの対応する「ソース」ノードを参照して、エンティティ・オブジェクトのメッセージ・バンドル・ファイルを検証できます。「構造」ウィンドウには、アプリケーション・ナビゲータで選択したコンポーネントの実装ファイルが表示されます。
例4-4は、コントロール・ヒントの情報が表示されたメッセージ・バンドル・ファイルのサンプルを示しています。各String配列の最初のエントリはメッセージ・キーで、2番目のエントリはこのキーに対応するロケール固有のString値です。
例4-4 プロジェクト・メッセージ・バンドルに格納されるロケールに依存したコントロール・ヒント
AddressUsageEO_OwnerTypeCode_Error_0=Invalid OwnerTypeCode.
AddressUsageEO_UsageTypeCode_Error_0=Invalid UsageTypeCode.
OwnerTypeCode_CONTROLTYPE=105
PaymentOptionEO_RoutingIdentifier_Error_0=Please enter a valid routing identifier.
PaymentOptionsEO_PaymentTypeCode_Error_0=Invalid PaymentTypeCode.
PaymentTypeCode_CONTROLTYPE=105
PaymentOption_AccountNumber=Please enter a valid Account Number
MinPrice_FMT_FORMATTER=oracle.jbo.format.DefaultCurrencyFormatter
CostPrice_FMT_FORMATTER=oracle.jbo.format.DefaultCurrencyFormatter
UnitPrice_FMT_FORMATTER=oracle.jbo.format.DefaultCurrencyFormatter
OrderEO_GiftMessage=Please supply a message shorter than 200 characters
OrderEO=Please supply a gift message
DiscountBaseEO_DiscountAmount=Discount must be between 0 and 40%
oracle.fodemo.storefront.entities.PaymentOptionEO.ExpireDate_FMT_FORMAT=mm/yy
#Date range validation for ValidFrom and ValidTo dates
PaymentOptionEO_invalidDateRange_Error_0=Date range is invalid. {0} must be greater than {1}.
PaymentOptionEO_DateRange_Error_0=Invalid date range.{0} should be greater than {1}.
oracle.fodemo.storefront.entities.PaymentOptionEO.ValidFromDate_LABEL=Valid From Date
oracle.fodemo.storefront.entities.PaymentOptionEO.ValidToDate_LABEL=Valid To Date
OrderItemsVO_ImageId_Rule_0=ImageId not found
oracle.fodemo.storefront.store.queries.AddressesVO.Address1_LABEL=Address
oracle.fodemo.storefront.store.queries.AddressesVO.PostalCode_LABEL=Post Code or ZIP
. . .
JDeveloperでコントロール・ヒントおよびその他の翻訳可能文字列の保存に使用されるリソース・バンドル・オプションは、「プロジェクト・プロパティ」ダイアログの「リソース・バンドル」ページのオプションで指定します。このオプションは、デフォルトで「プロパティ・バンドル」に設定され、.propertiesファイルが生成されます。
プロジェクトのリソース・バンドル・オプションの設定手順:
アプリケーション・ナビゲータで、プロジェクトを右クリックし、「プロジェクト・プロパティ」を選択します。
「リソース・バンドル」をクリックします。
プロジェクト設定またはカスタム設定のどちらを使用するかを選択します。
「カスタム設定を使用」を選択すると、現在のプロジェクトの作業のみに設定が適用されます。これらの設定はセッション間で保存されますが、プロジェクトには記録されないため、他のユーザーとは共有できません。「プロジェクト設定を使用」を選択すると、選択内容がプロジェクトに記録され、プロジェクトを使用する他のユーザーと共有できます。
次のオプションを選択または宣言して、設定を指定します。
バンドルの自動同期化
ハードコード化された変換可能な文字列に関して警告
常に説明の入力を要求
これらのオプションの詳細は、「ヘルプ」をクリックしてオンライン・ヘルプを参照してください。
リソース・バンドルの粒度を選択します。
1プロジェクト当たり1バンドル(デフォルト)
1ファイル当たり1バンドル
複数の共有バンドル(ADFビジネス・コンポーネントでは使用不可)
使用するファイルのタイプを選択します。
リスト・リソース・バンドル
ListResourceBundleクラスは、名前/値の配列でリソースを管理します。各ListResourceBundleクラスは、Javaクラス・ファイルに格納されます。ListResourceBundleクラスには、ロケール固有のオブジェクトを格納できます。
プロパティ・バンドル(デフォルト)
翻訳可能なテキストを名前/値のペアで格納するテキスト・ファイルです。プロパティ・ファイル(例4-4に示すようなファイル)には、Stringオブジェクトのみに対応する値を格納できます。他のタイプのオブジェクトを格納する必要がある場合は、かわりにListResourceBundleを使用する必要があります。
Xliffリソース・バンドル
XML Localization Interchange File Format (XLIFF)は、ローカリゼーション・データの交換に対応したXMLベースのフォーマットです。
「OK」をクリックして設定を適用し、ダイアログを閉じます。
翻訳可能な文字列(属性コントロール・ヒントなど)を定義する場合は、「テキスト・リソースの選択」ダイアログで新しい文字列を入力したり、オブジェクトのデフォルトのリソース・バンドルで定義済の文字列を選択できます。必要に応じて、異なるリソース・バンドルを使用することもできます。これは、プロジェクト間で共有される共通のリソース・バンドルを使用する場合に便利です。
デフォルト以外のリソース・バンドルの設定を使用するには:
「テキスト・リソースの選択」ダイアログで、使用するバンドルを「リソース・バンドル」ドロップダウン・リストから選択します。
目的のリソース・バンドルが「リソース・バンドル」ドロップダウン・リストにない場合は、「参照」アイコンをクリックして、使用するリソース・バンドルを検索して選択します。
ダイアログには、選択したリソース・バンドルで現在定義されている文字列が表示されます。
既存の文字列を選択し、「選択」をクリックするか、新しい文字列を入力して「保存して選択」をクリックします。
新しい文字列を入力すると、選択したリソース・バンドルに書き込まれます。
ADFビジネス・コンポーネントを使用して作成したアプリケーションのモデル・レイヤーを国際化するには、各コンポーネントのメッセージ・バンドル・ファイルの翻訳バージョンを生成する必要があります。たとえば、OrdersImplMsgBundleメッセージ・バンドルのイタリア語バージョンは、OrdersImplMsgBundle_itという名前のクラスになり、さらに限定されたスイス・イタリア語バージョンは、OrdersImplMsgBundle_it_chという名前になります。通常は、これらのクラスによってベース・メッセージ・バンドル・クラスが拡張され、これらのクラスにローカライズが必要なメッセージ・キーのエントリとともにローカライズされたこれらの翻訳が含まれます。
例4-5は、エンティティ・オブジェクトのメッセージ・バンドルのイタリア語バージョンを示しています。このイタリア語バージョンでは、RequestDateおよびAssignedDateのフォーマット・マスクがdd/MM/yyyy HH:mmに変更されています。これにより、イタリア語のユーザーには、2006年5月3日の日付値は、デフォルトのメッセージ・バンドルのフォーマット・マスクで生成される05/03/2006 15:55ではなく03/05/2006 15:55として表示されます。オーバーライドされたgetContents()メソッドに注意してください。これは、スーパークラス・バンドルからオーバーライドされていない文字列にマージされた、より限定された翻訳文字列によるメッセージ配列を戻します。実行時には、現在のユーザーのロケール設定に基づいて適切なメッセージ・バンドルが自動的に使用されます。
例4-5 イタリア語にローカライズされたエンティティ・オブジェクト・コンポーネントのメッセージ・バンドル
package devguide.model.entities.common;
import oracle.jbo.common.JboResourceBundle;
public class ServiceRequestImplMsgBundle_it
extends ServiceRequestImplMsgBundle {
static final Object[][] sMessageStrings = {
{ "AssignedDate_FMT_FORMAT", "dd/MM/yyyy HH:mm" },
{ "AssignedDate_LABEL", "Assegnato il" },
{ "AssignedTo_LABEL", "Assegnato a" },
{ "CreatedBy_LABEL", "Aperto da" },
{ "ProblemDescription_LABEL", "Problema" },
{ "RequestDate_FMT_FORMAT", "dd/MM/yyyy HH:mm" },
{ "RequestDate_LABEL", "Aperto il" },
{ "RequestDate_TOOLTIP", "La data in cui il ticket è stato aperto" },
{ "Status_LABEL", "Stato" },
{ "SvrId_LABEL", "Ticket" }
};
public Object[][] getContents() { return super.getMergedArray(sMessageStrings, super.getContents()); }
}
ビジネス・ロジック・グループでは、関連するコントロール・ヒント、デフォルト値および検証ロジックをカプセル化できます。ビジネス・ロジック・グループは、ベース・エンティティとは別に独自のファイルに保存され、現在の行のコンテンツ値に基づいて動的に有効にできます。
これは、ロケールごとの専門チームによって管理される多数のロケール固有の検証(国別識別子や税法チェックなど)が定義されるHRアプリケーションなどで有効です。ビジネス・ロジック・グループでは、これらの検証を個別のファイルに格納するため管理が容易になり、必要時にのみロードすることでパフォーマンスが最適化されます。
各ビジネス・ロジック・グループには、ビジネス・ロジック・ユニットのセットが格納されます。各ユニットでは、ビジネス・ロジック・グループに関連付けられた属性値に基づいて、エンティティでロードされるビジネス・ロジックのセットを識別します。
たとえば、Employeeエンティティ・オブジェクトにビジネス・ロジック・グループを定義し、EmpRegion属性を識別子として指定できます。次に、リージョンごとにビジネス・ロジック・ユニットを定義し、各リージョンで従業員の給与に範囲バリデータを指定します。Employeeエンティティから行がロードされると、(EmpRegion属性の値に基づいて)EmpSalary属性の適切なバリデータがロードされます。
Fusion Order DemoアプリケーションのStoreFrontモジュールから別の例をあげると、PersonEOエンティティ・オブジェクトは、識別子属性としてPersonTypeCodeを使用する、PersonTypeCodeGroupと呼ばれるビジネス・ロジック・グループを持ちます。この属性には3つの有効な値(CUST、STAFFおよびSUPP)があるため、対応するビジネス・ロジック・ユニットが3つあります。
このシナリオでは、各ビジネス・ロジック・ユニットにはそのユーザー・タイプのみに関連する新規または修正済ビジネス・ロジックが含まれます。
CUSTビジネス・ロジック・ユニットには、顧客に関連するロジックが含まれます。たとえば、すべての顧客が電話番号を持っている必要があるため、これには電話番号をチェックするバリデータが含まれます。
STAFFビジネス・ロジック・ユニットには、スタッフ・メンバーに関連するロジックが含まれます。たとえば、これには信用限度を制限するバリデータが含まれます。
SUPPビジネス・ロジック・ユニットには、サプライヤに関連するロジックが含まれます。たとえば、関連会社からサプライヤへのコンタクトはできないようにしているため、これにはContactByAffiliatesFlag属性がNに設定されていることを確認するバリデータが含まれます。
エンティティ・オブジェクトのビジネス・ロジック・グループは、概要エディタから作成します。
ビジネス・ロジック・グループを作成するには:
「アプリケーション・ナビゲータ」で、ビジネス・ロジック・グループを作成するエンティティをダブルクリックします。
概要エディタで、「一般」ナビゲーション・タブをクリックします。
「一般」ページで、「ビジネス・ロジック・グループ」セクションを拡張し、「追加」アイコンをクリックします。
作成ダイアログで、適切なグループ識別子属性を選択し、グループの名前を指定します。
|
ヒント: コードの可読性を高めるには、識別子を反映するようなグループ名にします。たとえば、グループ識別子属性がPersonTypeCodeの場合は、ビジネス・ロジック・グループの名前をPersonTypeCodeGroupにします。 |
「OK」をクリックします。
新しいビジネス・ロジック・グループが概要エディタの表に追加されます。グループを作成すると、ビジネス・ロジック・ユニットを追加できます。
ビジネス・ロジック。ユニットは「新規ギャラリ」から作成できます。また、ビジネス・ロジック・グループを格納するエンティティのポップアップ・メニューから直接作成することもできます。
ビジネス・ロジック・ユニットを作成するには:
「アプリケーション・ナビゲータ」で、ビジネス・ロジック・グループを格納するエンティティを右クリックし、ポップアップ・メニューからエンティティ・ビジネス・ロジック・ユニットの作成を選択します。
「ビジネス・ロジック・ユニットの作成」ダイアログで、ベース・エンティティの名前を指定し、適切なビジネス・ロジック・グループを選択します。
ビジネス・ロジック・ユニットの名前を入力します。
各ビジネス・ロジック・ユニットの名前には、このビジネス・ロジック・グループに関連付けられているグループ識別子属性の有効値を反映する必要があります。たとえば、グループ識別子属性がPersonTypeCodeの場合、STAFFのPersonTypeCode値に関連付けられているビジネス・ロジック・ユニットの名前はSTAFFにする必要があります。
ビジネス・ロジック・ユニットのパッケージを指定します。
|
注意: ビジネス・ロジック・ユニットのパッケージは、ベース・エンティティまたはビジネス・ロジック・グループのパッケージと同じにする必要はありません。これにより、コア・アプリケーションと別にビジネス・ロジック・ユニットを開発して配信できます。 |
「OK」をクリックします。
JDeveloperでは、概要エディタでビジネス・ロジック・ユニットを作成して開きます。「アプリケーション・ナビゲータ」のビジネス・ロジック・ユニットに表示される名前は、EntityName_BusLogicGroupName_BusLogicUnitNameの形式で、エンティティ・オブジェクトの名前とビジネス・ロジック・グループが含まれます。たとえば、PersonEOエンティティ・オブジェクトのPersonTypeCodeGroupビジネス・ロジック・グループにCUSTという名前でビジネス・ロジック・ユニットを作成する場合、表示されるビジネス・ロジック・ユニット名はPersonEO_PersonTypeCodeGroup_CUSTになります。
ビジネス・ロジック・ユニットを作成すると、そのビジネス・ロジック・ユニットに対してビジネス・ロジックを再定義できます。
ビジネス・ロジック・ユニットを作成したら、これを概要エディタで開き、ベース・エンティティで行う場合(エンティティレベルのバリデータを追加するなど)と同様に、ビジネス・ロジックを追加できます。
ビジネス・ロジック・ユニットにエンティティ・バリデータを追加するには:
「アプリケーション・ナビゲータ」で、ビジネス・ロジック・ユニットをダブルクリックします。
概要エディタで、「ビジネス・ルール」ナビゲーション・タブをクリックします。
「ビジネス・ルール」ページで、Entity Validatorsフォルダを選択し、「追加」アイコンをクリックします。
検証ルールを定義し、「OK」をクリックします。
たとえば、Fusion Order DemoアプリケーションのStoreFrontモジュールのPersonEOエンティティ・オブジェクトは、PersonEO_PersonTypeCodeGroup_CUSTと呼ばれるビジネス・ロジック・ユニットを持ちます。このビジネス・ロジック・ユニットには、電話番号の存在をチェックするエンティティ・バリデータがあり、顧客であるすべてのユーザーが電話番号を持っていることを確認します。
概要エディタでビジネス・ロジック・ユニットの「属性」ページを表示すると、属性表の「拡張」列に、属性がビジネス・ロジック・ユニットで拡張されていることが表示されます。拡張属性は、ビジネス・ロジック・ユニットではなく、ベース・エンティティでのみ編集できます。ベース・エンティティではなくビジネス・ロジック・ユニットで変更する場合は、編集する前に、ビジネス・ロジック・ユニットで属性をオーバーライド済として定義する必要があります。
ビジネス・ロジック・ユニットの属性をオーバーライドするには:
「アプリケーション・ナビゲータ」で、ビジネス・ロジック・ユニットをダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックします。
「属性」ページで、目的の属性を選択し、 「オーバーライド」ボタンをクリックします。
属性をオーバーライドしたら、属性をダブルクリックし、「属性の編集」ダイアログで開くと、通常どおりに編集できます。オーバーライドされた属性では、コントロール・ヒント、バリデータおよびデフォルト値の編集のみ行えます。
ビジネス・ロジック・グループを作成すると、ベース・エンティティのXMLファイルのグループに参照が追加されます。例4-6は、ビジネス・ロジック・グループのベース・エンティティのXMLファイルに追加されたコードを示しています。
例4-6 ビジネス・ロジック・グループのベース・エンティティのXMLコード
<BusLogicGroup
Name="PersonTypeCodeGroup"
DiscrAttrName="PersonTypeCode"/>
ビジネス・ロジック・ユニットを作成すると、エンティティ・オブジェクトのXMLファイルと同様のXMLファイルが生成されます。例4-7は、ビジネス・ロジック・ユニットのXMLコードを示しています。
|
注意: ビジネス・ロジック・ユニットのパッケージは、ベース・エンティティまたはビジネス・ロジック・グループのパッケージと同じにする必要はありません。これにより、コア・アプリケーションと別にビジネス・ロジック・ユニットを開発して配信できます。 |
例4-7 ビジネス・ロジック・ユニットのXMLコード
<Entity
xmlns="http://xmlns.oracle.com/bc4j"
Name="PersonEO_PersonTypeCodeGroup_CUST"
Version="11.1.1.54.6"
Extends="oracle.fodemo.storefront.entities.PersonEO"
DBObjectType="table"
DBObjectName="PERSONS"
BindingStyle="OracleName"
UseGlueCode="false"
BusLogicGroupName="PersonTypeCodeGroup"
BusLogicUnitName="CUST"
xmlns:validation="http://xmlns.oracle.com/adfm/validation">
<DesignTime>
<Attr Name="_codeGenFlag2" Value="Access"/>
<AttrArray Name="_publishEvents"/>
</DesignTime>
<validation:ExpressionValidationBean
Name="PersonEO_PersonTypeCodeGroup_CUST_Rule_0"
OperandType="EXPR"
Inverse="false">
<validation:MsgIds>
<validation:Item
Value="CUST_PHONE_REQUIRED"/>
</validation:MsgIds>
<validation:TransientExpression>
<![CDATA[if (PhoneNumber == null && MobilePhoneNumber == null)
return false;
else return true;]]>
</validation:TransientExpression>
</validation:ExpressionValidationBean>
<ResourceBundle>
<PropertiesBundle
PropertiesFile="oracle.fodemo.storefront.entities.common.PersonEO_PersonTypeCodeGroup_CUSTMsgBundle"/>
</ResourceBundle>
</Entity>
実行時にアプリケーションで行がロードされると、適用するビジネス・ロジック・ユニットがエンティティ・オブジェクトによって決定されます。
ベース・エンティティには、ビジネス・ロジック・グループのリストが格納されています。各グループは、エンティティの属性値を参照し、この値によってそれぞれのグループにロードするビジネス・ロジック・ユニットが決定されます。この評価は、ロードされる行ごとに実行されます。
ロードするビジネス・ロジック・ユニットを決定するロジックが簡単な属性値ではなく複雑な場合は、エンティティ・オブジェクトに一時属性を作成し、Groovy式を使用して一時属性の値を指定できます。
エンティティ・オブジェクトには、通常のエンタープライズ・ビジネス・アプリケーションの実装を簡略化するための様々な宣言的機能が用意されています。タスクによっては、宣言的機能のみでニーズが満たされる場合があります。エンティティ・オブジェクトの基本的な永続機能を記述する宣言的な実行時機能はこの項で説明しますが、宣言的な検証およびビジネス・ルールについては、第7章「検証とビジネス・ルールの宣言的な定義」で説明します。
|
注意: 必要に応じて、宣言的動作を超えて、より複雑なビジネス・ロジックまたは検証規則をビジネス・ドメイン・レイヤーに実装することができます。カスタム・コードを使用した最も一般的なエンティティ・オブジェクトの拡張方法は、第8章「プログラムによる検証とビジネス・ルールの実装」を参照してください。 |
またアプリケーションを開発する際の注意点として、プログラム的または宣言的にビジネス・ロジックを実装する場合、エンティティ・オブジェクトまたはビュー行の属性が特定の順序に従って設定されることを想定しないようにすることが重要です。順序が想定されていると、それとは異なる順序でエンド・ユーザーが属性値を入力した場合に問題が発生します。
エンティティ・オブジェクトの宣言的な実行時動作を構成するには、概要エディタを使用します。
エンティティ・オブジェクトの宣言的な実行時動作を構成するには:
「アプリケーション・ナビゲータ」で、エンティティ・オブジェクトをダブルクリックします。
概要エディタで、「一般」ナビゲーション・タブをクリックしてエンティティ・オブジェクトの名前およびパッケージを表示し、関連付けられたスキーマ、代替キー、カスタム・プロパティおよびセキュリティなど、オブジェクトのエンティティ・レベルでの様々な構成を行います。
「代替キー」セクションでは、代替主キーとして機能できる、データベースにマッピングされたエンティティ・オブジェクト属性を選択できます。代替キーの詳細は、4.10.15項「代替キー値の定義方法」を参照してください。
「チューニング」セクションでは、単一のトランザクションで同じタイプの複数のエンティティを作成、変更または削除するときのデータベース操作をより効率的にするためのオプションを設定できます。詳細は、38.3項「バッチ更新の使用」を参照してください。
「カスタム・プロパティ」セクションでは、実行時にエンティティでアクセス可能なカスタム・メタデータを定義できます。
「セキュリティ」セクションでは、エンティティについてロール・ベースの更新可能権限を定義できます。詳細は、第30章「Fusion WebアプリケーションでのADFセキュリティの有効化」を参照してください。
「ビジネス・ロジック・グループ」セクションでは、ビジネス・ロジック・グループと追加および削除できます。詳細は、4.8項「ビジネス・ロジック・グループの定義」を参照してください。
「属性」ナビゲーション・タブをクリックして、エンティティ・オブジェクトに関連するデータを示す属性を作成または削除し、検証規則、カスタム・プロパティおよびセキュリティなど、属性の様々な構成を行います。
属性を選択し、「編集」アイコンをクリックして属性のプロパティにアクセスします。これらのプロパティの設定方法の詳細は、4.10項「属性プロパティの設定」を参照してください。
|
ヒント: エンティティの属性名のリストが長い場合、目的の属性を簡単に見つける方法があります。「構造」ウィンドウの「属性」ノードが開かれた状態で属性名を入力すると、入力した文字に応じて属性がインクリメンタル検索され、ツリー内のその名前が表示されます。 |
「ビジネス・ルール」ナビゲーション・タブをクリックして、エンティティ・オブジェクトとその属性の宣言的バリデータを定義します。詳細は、第7章「検証とビジネス・ルールの宣言的な定義」を参照してください。
「Java」ナビゲーション・タブをクリックし、カスタムJava実装に対して生成するクラスを選択します。Javaクラスは、プログラム的なビジネス・ルールの定義などに使用できます(第8章「プログラムによる検証とビジネス・ルールの実装」を参照)。
「ビジネス・イベント」ナビゲーション・タブをクリックし、エンティティ・オブジェクトが、その状態の変更を他に通知する際に使用できるイベント(およびオプションで、配信イベントに含めるエンティティ・オブジェクトの属性の一部または全部)を定義します。ビジネス・イベントの詳細は、4.11項「ビジネス・イベントの作成」を参照してください。
「ビュー・アクセッサ」ナビゲーション・タブをクリックし、ビュー・アクセッサを作成および管理します。詳細は、10.4.1項「エンティティ・オブジェクトまたはビュー・オブジェクトのビュー・アクセッサの作成方法」を参照してください。
宣言的なフレームワークによって、属性プロパティを簡単に設定できます。すべてのケースにおいて、これらのプロパティは、概要エディタの「属性」ページからアクセスできる「属性の編集」ダイアログで設定します。
「永続的」プロパティにより、基礎となる表内の列に属性値が対応するか、単なる一時的な値であるかを制御します。属性が永続的である場合、「データベース列」領域を使用して、属性に対応する基礎となる列の名前を変更し、精度およびスケール情報を使用してその列型を指定できます(VARCHAR2(40)やNUMBER(4,2)など)。エンティティ・オブジェクトは、実行時にこの情報に基づいて、属性値の最大長および精度/スケールを設定し、値が要件を満たさない場合は例外をスローします。
「表からのビジネス・コンポーネント」ウィザードと「エンティティ・オブジェクトの作成」ウィザードでは、各エンティティ・オブジェクト属性のJava型は、関連付けられている列のデータベース列型のSQL型から推測されます。
|
注意: プロジェクトの「型マップ」設定は、Javaデータ型の決定にも役割を果します。ビジネス・コンポーネント・プロジェクトを初期化する場合は、ビジネス・コンポーネントが作成される前に「型マップ」設定を指定します。詳細は、3.3.1項「接続、SQLスタイルおよび型マップの選択」を参照してください。 |
(「属性の編集」ダイアログの)「属性タイプ」フィールドでは、エンティティ属性のJava型を目的の型に変更できます。「データベース列タイプ」フィールドには、属性がマップされている、基礎となるデータベース列のSQL型が表示されます。「データベース列」の「名前」フィールドにより、属性がマップされる列が制御されます。
エンティティ・オブジェクトは、表4-1に示す様々な列型の表を処理できます。java.lang.Stringクラスを除いて、デフォルトのJava属性タイプはすべてoracle.jbo.domainおよびoracle.ord.imパッケージに格納されており、対応する型のOracleデータベースのデータを効率的に処理できるようサポートされています。「属性タイプ」フィールドのドロップダウン・リストには、サポートされているその他の多数の共通のなJava型が含まれています。
表4-1 デフォルトのエンティティ・オブジェクトの属性タイプのマッピング
| Oracleの列型 | エンティティの列型 | エンティティのJava型 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
注意: ここで示した型以外にも、java.io.Serializableインタフェースが実装されていることを前提に、任意のJavaオブジェクト型をエンティティ・オブジェクトの属性の型として使用できます。 |
VARCHAR2(n)などの最大長の定義をサポートする型を使用する場合、(「属性の編集」ダイアログの)「データベース列タイプ」フィールドには、値の一部として属性の最大長が含まれます。たとえば、データベースのVARCHAR2(10)列に基づく属性の場合、データベース列の型としてVARCHAR2(10)が表示され、最初に最大長として10文字が示されます。なんらかの理由により、String値の属性の最大長を、基礎となる列で使用可能な文字数より少ない文字数に制限する必要がある場合は、データベース列タイプの値の最大長を変更します。
たとえば、PERSONS表のEMAIL列がVARCHAR2(50)である場合、デフォルトでは、Personsエンティティ・オブジェクトのEmail属性も同じ型に設定されます。ただし、実際の電子メール・アドレスが常に8文字以下である場合は、Email属性のデータベース列の型をVARCHAR2(8)に更新し、エンティティ・オブジェクト・レベルでの最大長を8文字に設定できます。
これは、NUMBER(p[,s])のように精度やスケールの定義をサポートするデータベース列の型に関連する属性についても同様です。たとえば、データベースのNUMBER(7,2)列に基づく属性の精度を5、スケールを1に制限するには、「データベース列タイプ」フィールドの値をNUMBER(5,1)に更新します。
「更新可能」プロパティにより、特定の属性値をいつ更新できるかを制御します。選択できる値は次のとおりです。
常に: 属性は常に更新可能です。
なし: 属性は読取り専用です。
新規の間: エンティティ行を初めて作成するトランザクション中は属性を設定できますが、データベースへのコミットが成功した後、属性は読取り専用になります。
|
注意: 更新可能性の静的な宣言に加えて、エンティティのisAttributeUpdateable()メソッドにカスタム・コードを追加して、実行時に属性の更新可能性を決定することもできます。 |
フィールドが必須の場合は、「必須」チェック・ボックスを選択します。必須プロパティは、実行時、(属性バリデータの実行時ではなく)エンティティ・レベルの検証が行われる際に適用されます。
「主キー」プロパティにより、属性がエンティティを一意に識別するキーの一部であるかどうかを指定します。通常、主キーには単一属性を使用しますが、複数属性の主キーも完全にサポートされています。
実行時には、getKey()メソッドを使用して任意のエンティティ行に関連するKeyオブジェクトにアクセスすると、このKeyオブジェクトには、このエンティティ・オブジェクトの主キー属性の値が含まれます。このエンティティ・オブジェクトに複数の主キー属性がある場合、Keyオブジェクトにはこれらの各値が含まれます。これらの値が、エンティティ・オブジェクト定義で対応する主キー属性と同じ相対順序で表示されると理解することが重要です。
たとえば、OrderItemEOエンティティ・オブジェクトには、OrderIdおよびLineItemIdという複数の主キー属性があります。概要エディタの「エンティティ属性」ページでは、OrderIdが先頭で、LineItemIdが2番目です。OrderItemEO型のエンティティ行のKeyオブジェクトによってカプセル化された値の配列では、これらの2つの属性値がこれとまったく同じ順序になります。
「エンティティ属性」ページでは、複数の主キー属性がどのような順序で表示されているかを理解しておくことが非常に重要です。findByPrimaryKey()を使用して複数属性の主キーを持つエンティティを検索する場合、作成したKeyオブジェクトでこれら複数の主キー属性の順序が間違っていると、エンティティ行が期待したとおりに検出されません。
「値のタイプ」が「リテラル」に設定されている場合、(「属性の編集」ダイアログの)「値」フィールドには、属性の静的なデフォルト値を指定できます。たとえば、ServiceRequestエンティティ・オブジェクトのStatus属性のデフォルト値をOpenに設定したり、Userエンティティ・オブジェクトのUserRole属性のデフォルト値をuserに設定できます。
|
注意: 1つのエンティティ・オブジェクトに複数の属性がデフォルト設定される場合は、エンティティ・オブジェクトのXMLファイルにおいてそれらの属性が表示されている順にデフォルト設定されます。 |
属性のデフォルト値は、Groovy式を使用して定義できます。実行時にデフォルト値を変更できるようにする場合はこの方法が便利ですが、デフォルト値が常に同じ場合は、(「属性の編集」ダイアログの)「デフォルト」フィールドを使用すると、より簡単に値を表示および管理できます。Groovyの使用の詳細は、3.6項「Groovyサポートの概要」を参照してください。
Groovy式を使用してデフォルト値を定義する手順:
アプリケーション・ナビゲータで、エンティティをダブルクリックし、概要エディタを開きます。
概要エディタで、「属性」ナビゲーション・タブをクリックします。
「属性」ページで、目的の属性を選択し、 「編集」ボタンをクリックします。
「属性の編集」ダイアログで、「値のタイプ」から「式」を選択し、(「値」フィールドの隣の)「編集」をクリックします。
表示されているフィールドにGroovy式を入力し、「OK」をクリックします。
「OK」をクリックします。
Groovy式を使用してデフォルト値を定義すると、<TransientExpression>タグがエンティティ・オブジェクトのXMLファイルの適切な属性内に追加されます。例4-11は、デフォルト値に現在の日付を取得するGroovy式のサンプルXMLコードを示しています。
基礎となる列値が、挿入または更新の操作時にデータベース・トリガーによって更新される場合、(「属性の編集」ダイアログの)「次の後にリフレッシュ」領域の「挿入」チェック・ボックス、または「更新」チェック・ボックスをそれぞれ選択することにより、フレームワークを通じて変更された値を自動的に取得し、常にエンティティ・オブジェクトとデータベース行の同期を取ることができます。エンティティ・オブジェクトは、INSERTまたはUPDATEを実行しながらOracle SQLのRETURNING INTO機能を使用して、変更された列を1回のデータベースのラウンドトリップでアプリケーションに戻します。
|
注意: DBLINKを介してリモート表に解決されるシノニムのエンティティ・オブジェクトを作成する場合、この機能を使用すると、実行時に次のようなエラーが発生します。JBO-26041: Failed to post data to database during "Update" ## Detail 0 ## ORA-22816: unsupported feature with RETURNING clause このようなデータベース制限を回避する技術は、38.6項「結合ビューまたはリモートDBLinkに基づくエンティティ・オブジェクト」を参照してください。 |
挿入後に属性がリフレッシュされる一般的なケースは、主キー属性の値がBEFORE INSERT FOR EACH ROWトリガーによって割り当てられる場合です。多くの場合、このトリガーにより、PL/SQLロジックを使用してデータベース順序から主キーが割り当てられます。例4-9は、この例を示しています。
例4-9 データベース順序から主キーを割り当てるPL/SQLコード
CREATE OR REPLACE TRIGGER ASSIGN_SVR_ID
BEFORE INSERT ON SERVICE_REQUESTS FOR EACH ROW
BEGIN
IF :NEW.SVR_ID IS NULL OR :NEW.SVR_ID < 0 THEN
SELECT SERVICE_REQUESTS_SEQ.NEXTVAL
INTO :NEW.SVR_ID
FROM DUAL;
END IF;
END;
「属性の編集」ダイアログでは、「タイプ」フィールドの値をDBSequenceという名前の組込みデータ型に設定すると、データベース順序によって主キーが自動的に割り当てられます。このデータ型を選択すると、「リフレッシュ」の「挿入後」チェック・ボックスが自動的に選択されます。
|
注意: 「順序」タブに表示されている順序名が設計時に使用されるのは、4.2.6項「エンティティ・オブジェクトからのデータベース表の作成方法」で説明されているデータベース表の作成機能を使用する場合のみです。ここで示す順序は、エンティティ・オブジェクトの基礎となる表とともに作成されます。 |
主キーがDBSequenceである新しいエンティティ行を作成すると、一意の負の数値が一時値として割り当てられます。この値は、このエンティティ行を作成するトランザクション中、主キーとして機能します。同じトランザクション内で一連の相関エンティティを作成する場合、その他の新しい関連エンティティ行にこの一時値を外部キー値として割り当てることができます。トランザクションのコミット時に、エンティティ・オブジェクトは、RETURNING INTO句を使用してINSERT操作を発行し、実際にデータベースのトリガーによって割り当てられた主キー値を取得します。コンポジット関連では、先にこの一時的な負の値を外部キーとして使用していた新しい関連エンティティでは、マスターの実際の新しい主キーを反映してこの値が更新されます。
通常は、DBSequence値を持つ主キーの「更新可能」プロパティも「なし」に設定します。一時IDはエンティティ・オブジェクトによって割り当てられ、INSERT操作の後に実際のID値を使用してリフレッシュされます。エンド・ユーザーがこの値を更新する必要はありません。
コンポジット以外のアソシエーションでこの機能を実装する方法の詳細は、38.8.3.3項「DBSequenceの値が設定される主キーに基づくアソシエーションの理解」を参照してください。
実行時には、フレームワークによりエンティティ・オブジェクトの更新の上書きが自動的に検出され、作業中に別のユーザーによって更新およびコミットされたデータであることに気付かずにユーザーがこのデータを変更できないようにします。通常、このチェックは、基礎となる行がロックされているときにデータベース内で対応する現在の列値と各永続エンティティ属性の元の値を比較することによって実行されます。行の更新前に、エンティティ・オブジェクトによって、更新される行とデータベースの現在の状態の間に一貫性があるかどうかが検証されます。行とデータベースの状態の間に一貫性がない場合、エンティティ・オブジェクトではRowInconsistentExceptionが発生します。
更新の上書きの検出をより効率的にするには、エンティティが変更されるたびに値が更新されるエンティティの属性を特定します。通常、このような値には、行内のバージョン番号列や更新日付列などがあります。作成したデータベース・トリガーによって更新識別子の属性値を割り当て、(「属性の編集」ダイアログの)「次の後にリフレッシュ」領域の「挿入」オプション、および「更新」オプションを使用して、エンティティ・オブジェクトでこれらの値をリフレッシュできます。また、4.10.12項「履歴列を使用して作成および変更した日付を追跡する方法」で説明する履歴属性の機能を使用して、エンティティ・オブジェクトによって更新識別子の属性値の更新が管理されるように指定できます。ユーザーによる問合せ以降に行が変更されたかどうかを最も効率的な方法で検出するには、「更新識別子」オプションを選択し、更新識別子の属性値のみを比較します。
エンティティの作成日時や変更日時、作成者や変更者、エンティティの変更回数など、エンティティ・オブジェクトで履歴情報を追跡する必要がある場合は、(「属性の編集」ダイアログで)「履歴列」オプションが選択されている属性を指定します。
属性のデータ型がNumber、StringまたはDateであり、主キーの一部ではない場合、このプロパティを有効化して履歴監査用の属性値を自動的に管理できます。フレームワークにおける属性の処理方法は、次のような履歴属性のタイプの中からどれを指定するかによって異なります。
作成日付: この属性には、行が作成された日付のタイム・スタンプが移入されます。タイム・スタンプはデータベースから取得されます。
作成者: この属性には、行を作成したユーザーの名前が移入されます。ユーザー名は、SessionオブジェクトのgetUserPrincipleName()メソッドを使用して取得されます。
変更日付: この属性には、行が更新/作成された日付のタイム・スタンプが移入されます。
変更者: この属性には、行を作成/更新したユーザーの名前が移入されます。
バージョン番号: この属性には、行が作成または更新されるたびに増分するlong値が移入されます。
エンティティ・オブジェクトでは、OrderItemEOエンティティを作成するOrderEOエンティティなど、他のエンティティを作成(または構成)する場合、コンポジット動作が示されます。この付加的な実行時動作により、ネストされた他のエンティティ・オブジェクト部分の論理コンテナとしての役割が決定されます。この関係により、コンポジット・アソシエーションは、一時属性をベースに作成できません。
エンティティ・オブジェクトの構成で常に有効な機能については、次の項を参照してください。
別の機能およびこれらの動作に影響するプロパティについては、次の項を参照してください。
構成されるエンティティ・オブジェクトが作成されると、この値が既存のエンティティを所有する親のエンティティとして識別しているか確認するため、外部キー属性の値の存在がチェックされます。作成時に外部キーが検出されなかった場合や、既存のエンティティ・オブジェクトを識別しない値が検出された場合、エンティティ・オブジェクトでは、親エンティティが識別されていない状態で親のない子行が作成されないように、InvalidOwnerExceptionがスローされます。
|
注意: 外部キー属性の値の存在がチェックされたことにより、現在のトランザクションで新しい保留エンティティが検索される他、必要に応じてデータベース内の既存のエンティティが検索されます。 |
コンポジット動作により、構成する側のエンティティ・オブジェクトと構成される側のエンティティ・オブジェクトの両方が含まれるトランザクションで実行されるデータ操作言語(DML)操作が正しい順序で実行されたかどうかを確認します。たとえば、構成する側の新しい親エンティティ・オブジェクトに対するINSERT文は、構成される側の子エンティティ・オブジェクトに関連するDML操作の前に実行されます。
主キーが挿入時にリフレッシュするように構成されている新しいエンティティ行を保存すると、トリガーによって割り当てられた主キー値の取得後に、構成される側のエンティティの外部キー属性値が更新されて新しい主キー値が反映されます。
これ以外にも、アソシエーション作成ウィザードの「アソシエーション・プロパティ」ページまたは概要エディタの設定を介して制御可能なコンポジット関連機能が多数用意されています。図4-12は、2つのエンティティ・オブジェクトOrderItemEOとOrderEOの間のOrderItemsOrdersFkAssocアソシエーションが表示された「関連」ページを示しています。
構成される側の子が存在していても、構成する側の親の削除を有効化または禁止できます。「カスケード削除の実装」オプション(図4-12を参照)の選択が解除されている場合に、構成する側の親に構成される側の子が含まれる場合、構成する側のエンティティ・オブジェクトの削除は禁止されます。
このオプションが選択されている場合、構成する側のエンティティ・オブジェクトを、構成される側の子エンティティとともに無条件に削除できます。関連する「データベースのカスケード削除用に最適化」オプションの選択が解除されている場合、構成される側のエンティティ・オブジェクトでは、トランザクションのコミット時に通常のDELETE文が実行され、変更が永続的になります。このオプションが選択されている場合、データベースのON DELETE CASCADE制約によって対応する行の削除が処理されることを前提に、構成される側のエンティティではDELETE文は実行されません。
「カスケード更新キー属性」オプション(図4-12を参照)を選択すると、構成する側のエンティティの主キー値が変更される場合に、構成される側のエンティティの外部キー属性値が自動で更新されるよう設定できます。
「最上位コンテナのロック」オプション(図4-12を参照)を選択すると、構成される側の詳細エンティティ行の追加、削除または変更時に、変更を保存する前に、構成する側のエンティティをロックするかどうかを制御できます。
「トップレベルの履歴列の更新」オプション(図4-12を参照)を選択すると、構成される側の詳細エンティティ・オブジェクトの追加、削除または変更時に、構成する側の親エンティティの「変更者」および「変更日付」履歴属性を更新するかどうかを制御できます。
場合によっては、論理的に関連付けられた様々なオブジェクトに関する情報が1つのデータベース表に格納されることがあります。たとえば、給与計算アプリケーションでは、アルバイト、正社員、契約社員すべてが、EMPLOYEE_TYPE列を持つ1つのEMPLOYEES表に格納されることがあります。この場合、EMPLOYEE_TYPE列では、H、S、Cなどの値を使用して、特定の行がそれぞれアルバイト(Hourly)、正社員(Sararied)、契約社員(Contract)のいずれを表すのかを示します。多くの属性や動作はすべての従業員で同一の場合もありますが、特定のプロパティやビジネス・ロジックは従業員のタイプによって異なることがあります。
関連するオブジェクトの間に共通情報が存在する場合は、継承階層を使用してこのような異なるタイプのエンティティ・オブジェクトを表すと便利です。たとえば、すべての従業員に共通の属性およびメソッドは、ベースとなるEmployeeエンティティ・オブジェクトの一部とし、HourlyEmployee、SalariedEmployeeおよびContractEmployeeなどのサブタイプのエンティティ・オブジェクトでは、ベースとなるEmployeeオブジェクトを拡張し、別のプロパティや動作を追加します。「多相化識別子」属性設定を使用して、行のタイプを識別する属性の値を示します。継承の設定方法および使用方法は、38.7項「ビジネス・ドメイン・レイヤーでの継承の使用」を参照してください。
データベースの主キーは順序から生成されることが多く、様々な理由からユーザーへの公開を避けることが必要な場合があります。このため、多くのケースでは一意の代替キー値を使用すると便利です。たとえば、すべての顧客に一意の電子メール・アドレスを持たせるとします。顧客は電子メール・アドレスを変更する可能性があるため、主キーとしてはこの値を使用できませんが、それぞれの顧客に対してログインなどの目的で使用できる一意のフィールドを持たせる必要があります。
代替キーは、メソッドのfindByKeyクラスを介して直接行を参照する場合に便利です。代替キーは、中間層で効率的な一意性チェックを行う場合にもよく使用されます。値が一意であるかどうかの確認方法の詳細は、7.4.1項「キー値の一意性を確認する方法」を参照してください。
代替キーの定義には、「エンティティ制約の作成」ウィザードを使用します。
代替キー値を定義するには:
アプリケーション・ナビゲータで、エンティティ・オブジェクトを右クリックし、ポップアップ・メニューから「新規エンティティ制約」を選択します。
「エンティティ制約の作成」ウィザードの手順に従って、制約の名前を指定し、キーとして使用する属性(複数可)を選択します。
「プロパティ」ページで、「代替キー」を選択し、適切な「キー・プロパティ」オプションを選択します。
「キー・プロパティ」の詳細情報は、[F1]キーを押すか「ヘルプ」をクリックすると参照できます。
モデル・レイヤーから呼び出されたビジネス・イベントは、ビジネス・プロセスを起動する際や、Oracle Mediator経由で外部システム同期化をトリガーする際に役立ちます。
Oracle Mediatorでは、ビジネス・イベントをアクションにマッピングする宣言的サブスクリプションがサポートされています。つまり、あるコンポーネントでビジネス・イベント(新規顧客作成など)を定義して公開した後、別のコンポーネントでこのイベントをサブスクライブすると、このビジネス・プロセスが発生したときに通知されます。次に、サブスクライブ中のコンポーネントで、そのイベントに割り当てているアクション(新規顧客への挨拶メールの送信など)を実行できます。
ビジネス・イベントはエンティティ・レベルで宣言的に定義します。また、それらのイベントを呼び出す条件を指定できます。指定の基準を満たすビジネス・イベントは、変更されたデータが正常にコミットされたときに呼び出されます。ビジネス・イベントは、エンティティ・オブジェクトが正常に作成、更新または削除されたときにMediatorに発行されます。
ビジネス・イベントを実装するには、まずイベント定義を作成し、そのイベント定義をイベント・ポイントにマッピングし、その定義を公開します。ビジネス・イベントが公開されたら、別のコンポーネントからそのイベントをサブスクライブできます。
|
注意: マスター/ディテール関係で、有効日が指定された子から有効日が指定された親に対して呼び出されるようなビジネス・イベントを構成しないでください。子オブジェクトは親オブジェクトに対するイベントを呼び出すことができ、有効日が指定されたエンティティ・オブジェクトは更新および削除操作中に行が分割されるため、親と子が同じトランザクション中に更新されると、子オブジェクトは間違った親オブジェクトに対するイベントを呼び出す可能性があります。有効日が指定されたエンティティ・オブジェクトの詳細は、4.2.8項「特定の時点に関するデータを格納する方法」を参照してください。 |
イベント定義には、イベント・システムMediatorで公開および呼び出されるイベントが記述されます。イベント定義は、表4-2に示す要素とともに、エンティティ・オブジェクトのXMLファイルに格納されます。
イベント・ポイントは、イベントを呼び出せる場所です。コミットが正常に行われた時点で、表4-3に示すいずれかのイベント・ポイントをトランザクションのエンティティごとにMediatorに呼び出せます。
表4-3 Mediatorに呼び出されたイベント・ポイントの例
| DML型 | イベント名 | イベントの説明 |
|---|---|---|
|
CREATE |
EntityCreated |
新しいエンティティが作成されました。 |
|
UPDATE |
EntityUpdated |
既存のエンティティが更新されました。 |
|
DELETE |
EntityDeleted |
既存のエンティティが削除されました。 |
イベントはデフォルトで呼び出されることはなく、すべてのイベントがカスタムです。イベントを作成する場合、名前とDML操作を適宜指定できます。
イベント・ポイントごとに、どのイベント定義を特定のイベント・ポイントで呼び出すかを指定する必要があります。つまり、各イベント定義をイベント・ポイントに宣言的にマッピングする必要があります。
イベント配信がトランザクションの一部であるトランザクション・イベント配信は、このフレームワークではサポートされていません。
サブスクライバがイベントの受信を確認するまで公開元がその後の処理を待機する同期化イベントは、このフレームワークではサポートされていません。
ビジネス・イベントを作成するには、概要エディタの「ビジネス・イベント」ページを使用します。
ビジネス・イベントを作成する手順は、次のとおりです。
「アプリケーション・ナビゲータ」で、エンティティ・オブジェクトをダブルクリックします。
概要エディタで、「ビジネス・イベント」ナビゲーション・タブをクリックします。
「ビジネス・イベント」ページで、「イベント定義」セクションを拡張し、「新規」アイコンをクリックします。
「ビジネス・イベント定義の作成」ダイアログで、EmployeeContactInfoChangedなど、このイベントを説明する名前を指定します。
ペイロード表で、「新規」および「削除」をクリックし、このイベントの適切な属性を選択します。
または、セルをダブルクリックして、適切な属性を選択します。
|
注意: エンティティ属性列には、サポートされているタイプの属性のみ表示されます。ClobDomain属性はサポートされていますが、非常に大きいCLOBデータはパフォーマンスに影響を与えることがあります。 |
「送信された値」フィールドで、値を「常に」送信するか、「変更された場合のみ」送信するか選択します。
「変更された場合のみ」オプションを選択すると、ペイロードでは属性がオプションとみなされるため、最高のパフォーマンスが得られます。デフォルトの「常に」のままにすると、値が変更されているかどうかを問わず、ペイロードは属性を必要とします。ペイロードの効率姓の詳細は、4.11.6項「ペイロード・サイズに関する必知事項」を参照してください。
矢印ボタンを使用して、属性の順序を並べ替えます。
属性が表示される順序により、生成されたXSDでの順序が定義されます。XSDを使用してファブリック・メディエータとBPELプロセスを作成するため、最も頻繁にアクセスする属性を最上位に配置できます。
「OK」をクリックします。
定義するビジネス・イベントごとにこの手順を繰り返します。イベントの公開の詳細は、4.11.7項「ビジネス・イベントを公開する方法」を参照してください。
ビジネス・イベントを作成すると、エンティティ・オブジェクトのXMLファイルがイベント定義により更新されます。例4-10は、ビジネス・イベントのXMLコードの例を示しています。またJDeveloperでは、必須属性やオプション属性を指定できるイベント・スキーマの関連XSDファイルが生成されます。必須属性は、「送信された値」-「常に」に設定されたもので、オプション属性は、「送信された値」を「変更された場合のみ」に変更されたものです。
例4-10 ビジネス・イベントのXMLコード
<EventDef
Name="CustBusEvent1">
<Payload>
<PayloadItem
AttrName="Order.OrderId"/>
<PayloadItem
AttrName="LineItemId"/>
<PayloadItem
AttrName="ProductBase.ProductId"
SendOnlyIfChanged="true"/>
</Payload>
</EventDef>
例4-11は、ビジネス・イベントのXSDイベント・スキーマの例を示しています。
例4-11 ビジネス・イベントのXSDイベント・スキーマ
<?xml version = '1.0' encoding = 'UTF-8'?>
<xs:schema targetNamespace="/oracle/fodemo/storefront/entities/events/schema/OrderItemEO"
xmlns="/oracle/fodemo/storefront/entities/events/schema/OrderItemEO"
elementFormDefault="qualified" attributeFormDefault="unqualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="CustBusEvent1Info">
<xs:complexType>
<xs:sequence>
<xs:element name="Order.OrderId" type="DecimalValuePair" minOccurs="1"/>
<xs:element name="LineItemId" type="DecimalValuePair" minOccurs="1"/>
<xs:element name="ProductBase.ProductId" type="DecimalValuePair" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="ValuePair" abstract="true"/>
<xs:complexType name="DecimalValuePair">
<xs:complexContent>
<xs:extension base="ValuePair">
<xs:sequence>
<xs:element name="newValue" minOccurs="0">
<xs:complexType>
<xs:complexContent>
<xs:extension base="xs:anyType">
<xs:attribute name="value" type="xs:decimal"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
<xs:element name="oldValue" minOccurs="0">
<xs:complexType>
<xs:complexContent>
<xs:extension base="xs:anyType">
<xs:attribute name="value" type="xs:decimal"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
例4-12は、エンティティ・オブジェクトのEDLイベント定義の例を示しています。
例4-12 エンティティ・オブジェクトのEDLイベント定義
<definitions
targetNamespace="/oracle/fodemo/storefront/entities/events/edl/OrderItemEO"
xmlns:ns0="/oracle/fodemo/storefront/entities/events/schema/OrderItemEO"
xmlns="http://schemas.oracle.com/events/edl">
<schema-import
namespace="/oracle/fodemo/storefront/entities/events/schema/OrderItemEO"
location="OrderItemEO.xsd"/>
<event-definition name="CustBusEvent1">
<content element="ns0:CustBusEvent1Info"/>
</event-definition>
</definitions>
ビジネス・イベントのペイロードは、関連付けられたエンティティ・オブジェクトの属性で構成されます。ビジネス・イベントのペイロード属性は、イベントの作成者によって定義されます。自動的に最適化されるわけではありません。イベントを定義するときに、属性を「常に」または「変更された場合のみ」送信するとしてマークできます。作成時に起動されるイベントでは、新しい値のみが送信されます。更新または削除時に起動されるイベントでは、新規および既存の値が送信されますが、「送信された値」設定に基づいて該当の属性のみです。最高のパフォーマンスを得るには、削除イベントでは主キー属性のみを含める必要があります。
コンポジット・シナリオ(発注書と明細項目など)をサポートするために、子エンティティは親エンティティで定義されたイベントを呼び出すことができ、子エンティティで定義されたイベントには親エンティティからの属性を含めることができます。子エンティティが親エンティティのイベントを呼び出す場合、子エンティティによるイベントの呼出し回数に関係なく、トランザクションごとに特定のトップレベル・エンティティについて1つのイベントのみが呼び出されます。
エンティティ・サブタイプのケースでは(たとえば、Managerエンティティ・オブジェクトはUserエンティティのサブタイプです)、ADFビジネス・コンポーネントではビジネス・イベントのオーバーライドはサポートされません。ビジネス・イベントのサブスクライバは、イベント名を使用してイベントをリスンするため、イベントをオーバーライドすると、イベントのサブスクライバは自分に対するものではないペイロード・データを受信してしまう可能性があります。したがって、この機能はサポートされていません。
ビジネス・イベントを定義する際は、ClobDomain属性はサポートされていますが、非常に大きなCLOBデータはパフォーマンスに影響が与える可能性があることを考慮してください。
ビジネス・イベントを公開するには、エンティティ・オブジェクトの概要エディタの「ビジネス・イベント」ページを使用します。
ビジネス・イベントを公開する手順は、次のとおりです。
「アプリケーション・ナビゲータ」で、エンティティ・オブジェクトをダブルクリックします。
概要エディタで、「ビジネス・イベント」ナビゲーション・タブをクリックします。
「ビジネス・イベント」ページで、「イベント公開」セクションを拡張し、「イベント公開の編集」アイコンをクリックします。
「イベント公開の編集」ダイアログで、「新規」をクリックし、新しいイベントを作成します。
イベント列で新しいセルをダブルクリックし、適切なイベントを選択します。
イベント・ポイント列で対応するセルをダブルクリックし、適切なイベント・アクション・ポイントを選択します。
オプションで、呼出し条件Raise Conditions表を使用して、イベントを呼び出す条件を定義できます。
「OK」をクリックします。
ビジネス・イベントを作成したら、そのイベントをサブスクライブし、応答することができます。
始める前に:
ビジネス・イベントをサブスクライブするSCAプロジェクトを開きます(または作成します)。
ビジネス・イベントをサブスクライブする手順は、次のとおりです。
ファイル・システムを使用して、ビジネス・イベントのXSDおよびイベント定義ファイルをSCAプロジェクトのソース・パスにコピーします。
「アプリケーション・ナビゲータ」で、プロジェクトを右クリックして「新規」を選択します。
「新規ギャラリ」で、「SOA層」を展開し、「サービス・コンポーネント」を選択したら、「メディエータ」を選択し、「OK」をクリックします。
「メディエータの作成」ダイアログで、図4-13に示すように、「イベントのサブスクライブ」テンプレートを選択します。
「追加」アイコンをクリックして、イベントを追加します。
「イベント・チューザ」ダイアログで、「参照」アイコンをクリックしてイベントの定義ファイルにナビゲートして選択し、「OK」をクリックします。
「メディエータの作成」ダイアログでは、オプションで「一貫性」オプションを選択し、イベントの「フィルタ」を選択できます。
「OK」をクリックします。
結果として生成されたメディエータ(.mplanファイル)が概要エディタに表示されます。
「ルーティング・ルール」セクションの「追加」アイコンをクリックして、イベントへの対応方法のルールを追加できます。
エンティティ・オブジェクトを直接操作する場合、UIベースのクライアントまたはプログラム的クライアントは常に必要ではありません。アプリケーション・モジュールにアクセスし、そのデータ・モデル内のビュー・オブジェクトを直接操作する際、外部クライアント・プログラム以外には使用する必要がない場合もあります。第5章「ビュー・オブジェクトを使用したSQL問合せの定義」では、強力なアプリケーションを構築するために、ビュー・オブジェクトの柔軟なSQL問合せ機能に、エンティティ・オブジェクトのビジネス・ロジックとデータベースとの自動対話機能とを組み合せる簡単な方法について説明します。この組合せにより、現在のエンド・ユーザーのタスク上のニーズに対応するよう設計され、再使用可能なドメイン・ビジネス・オブジェクト・レイヤー内で一元管理されたビジネス・ロジックを共有する、完全に更新可能なアプリケーション・モジュールのデータ・モデルを作成できます。
ただし、まず重要なのは、ビュー・オブジェクトとエンティティ・オブジェクトを組み合せた能力の利用方法について学習する前に、これらのオブジェクト自体の使用方法について理解することです。これらのオブジェクトについて詳細に学習することにより、これらを単体で使用する必要があるときと、独自のアプリケーションでこれらを組み合せる必要があるときについて理解が深まります。
クライアントはエンティティ・オブジェクトを直接操作できないため、エンティティ・オブジェクトをプログラム的に操作するために記述するコードは、通常カスタム・アプリケーション・モジュール・クラス内または別のエンティティ・オブジェクトのカスタム・クラス内のカスタム・コードになります。
エンティティ行にアクセスするには、エンティティ定義と呼ばれる関連オブジェクトを使用します。実行時には、エンティティ・オブジェクトごとに対応するエンティティ定義を利用して、エンティティの構造を記述し、それにしたがってエンティティ・オブジェクトのインスタンスを管理します。アプリケーション・モジュールを作成し、そのカスタムJavaクラスを有効化した後に、特定の注文を戻すメソッドを作成する必要があるとします。これは、例4-13に示すretrieveOrderById()メソッドのようになります。
主キーによるエンティティ・オブジェクトを検索するには:
エンティティ定義を検索します。
OrderEOエンティティのエンティティ定義オブジェクトを取得するには、EntityDefImplクラスからインポートされた静的なgetDefinitionObject()メソッドにその完全修飾名を渡します。oracle.jbo.serverパッケージ内のEntityDefImplクラスにより、各エンティティ・オブジェクトのエンティティ定義が実装されます。
キーを作成します。
検索する主キー属性が含まれるKeyオブジェクトを作成します。この場合、メソッドに引数として渡される単一のorderId値が含まれるキーを作成します。
キーを使用してエンティティ・オブジェクトを検索します。
エンティティ定義のfindByPrimaryKey()メソッドを使用して、キーによってエンティティ・オブジェクトを検索し、getDBTransaction()メソッドを使用してアプリケーション・モジュールから取得できる現在のトランザクション・オブジェクトを渡します。エンティティ・オブジェクト行を示す具体的なクラスは、oracle.jbo.server.EntityImplクラスです。
オブジェクトまたはそのデータの一部をコール元に戻します。
例4-13は、この基本手順を使用して開発したretrieveOrderById()メソッドのコードの例を示しています。
例4-13 キーによるOrderEOエンティティ・オブジェクトの取得
/* Helper method to return an Order by Id */
private OrderEOImpl retrieveOrderById(long orderId) {
EntityDefImpl orderDef = OrderEOImpl.getDefinitionObject();
Key orderKey = OrderEOImpl.createPrimaryKey(new DBSequence(orderId));
return (OrderEOImpl)orderDef.findByPrimaryKey(getDBTransaction(),orderKey);
}
|
注意: oracle.jbo.Keyオブジェクト・コンストラクタは、より一般的な単一の属性値のキー以外にも、複数の属性キーの作成もサポートするためのオブジェクト配列を使用できます。 |
SQLコードを必要としないアクセッサ属性に基づいて、関連付けられたエンティティへアクセスするためのメソッドを作成できます。たとえば、メソッドfindOrderCustomer()によりオーダーを検索してから、オーダーに割り当てられた顧客を表す、関連付けられたPersonEOエンティティ・オブジェクトにアクセスします。アソシエーションを使用して1つのエンティティ・オブジェクトから別のエンティティ・オブジェクトへ簡単にアクセスする方法の詳細は、4.3項「アソシエーションの作成および構成」を参照してください。
同じアクセッサ属性を使用して同じ関連付けられたエンティティを検索するアプリケーション・モジュール内の既存のメソッドとの競合を避けるため、この機能をヘルパー・メソッドにリファクタし、必要に応じてアプリケーション・モジュール内の任意の場所で再使用できます。たとえば、注文を検索する機能は、retrieveOrderById()メソッド(例4-13を参照)によってリファクタされます。
アクセッサ属性を使用して関連付けられたエンティティ・オブジェクトにアクセスするには:
アクセッサ属性を使用して、関連付けられたエンティティを検索します。
findOrderCustomer()メソッドでは、retrieveOrderById()ヘルパー・メソッドを使用して、IDによってOrderEOエンティティ・オブジェクトを取得します。
アクセッサ属性を使用して関連付けられたエンティティにアクセスします。
属性のgetterメソッドを使用して、アソシエーション・アクセッサ名を渡し、関連の反対側にあるエンティティ・オブジェクトを取得できます。(アソシエーション・アクセッサをより直感的な名前に変更する方法の詳細は、4.3.3項「エンティティ・アソシエーションのアクセッサ名の変更方法」を参照してください。)
データの一部をコール元に戻します。
findOrderCustomer()メソッドでは、戻されたPersonEOエンティティに対してgetterメソッドを使用して、名前と姓を連結することにより、割り当てられた顧客の名前を戻します。
関連するPersonEOエンティティにアクセスするためにSQLを記述する必要はありません。OrderEOエンティティ・オブジェクトとPersonEOエンティティ・オブジェクト間のADFアソシエーションで取得された関連情報のみで、データ・ナビゲーションの一般的なタスクを自動化できます。
例4-14に、ヘルパー・メソッドを使用するfindOrderCustomer()のコードを示します。
例4-14 アクセッサ属性を使用した関連付けられたエンティティへのアクセス
/* Access an associated Customer entity from the Order entity */
public String findOrderCustomer(long orderId) {
//1. Find the OrderEO object
OrderEOImpl order = retrieveOrderById(orderId);
if (order != null) {
//2. Access the PersonEO object using the association accessor attribute
PersonEOImpl cust = (PersonEOImpl)order.getPerson();
if (cust != null) {
//3. Return attribute values from the associated entity object
return cust.getFirstName() + " " + cust.getLastName();
}
else {
return "Unassigned";
}
}
else {
return null;
}
}
エンティティ行を取得した後、エンティティ行は簡単に更新または削除できます。この処理は、例4-15に示すupdateOrderStatus()のようなメソッドを追加することにより実行できます。
エンティティ行を更新するには:
IDによってOrderを検索します。
updateOrderStatus()メソッドでは、retrieveOrderById()ヘルパー・メソッドを使用して、IDによってOrderEOエンティティ・オブジェクトを取得します。
1つ以上の属性を新しい値に設定します。
updateOrderStatus()メソッドでは、EntityImplクラスのsetAttribute()メソッドを使用して、Status属性の値を渡された新しい値に更新します。
トランザクションをコミットします。
updateOrderStatus()メソッドでは、アプリケーション・モジュールのgetDBTransaction()メソッドを使用して、現在のトランザクション・オブジェクトにアクセスし、commit()メソッドをコールしてトランザクションをコミットします。
例4-15 既存のエンティティ行の更新
/* Update the status of an existing order */
public void updateOrderStatus(long orderId, String newStatus) {
//1. Find the order
OrderEOImpl order = retrieveOrderById(orderId);
if (order != null) {
//2. Set its Status attribute to a new value
order.setOrderStatusCode(newStatus);
//3. Commit the transaction
try {
getDBTransaction().commit();
}
catch (JboException ex) {
getDBTransaction().rollback();
throw ex;
}
}
}
エンティティ行の削除の例もこれと同じですが、既存のエンティティを検索した後、トランザクションをコミットする前に、かわりに次の行を使用してエンティティを削除する点が異なります。
// Remove the entity instead! order.remove();
エンティティ定義を使用して既存のエンティティ行を検索する以外にも、エンティティ定義を使用して新しいエンティティ行を作成することもできます。製品エンティティの場合、例4-16のようなcreateProduct()メソッドを記述することにより、新しい製品の名前や説明を取得し、この製品に割り当てられた新しい製品IDを戻すことができます。この例は、ProductBaseEOエンティティ・オブジェクトのProductId属性がすでに更新され、その型がDBSequence型になっていること(4.10.10項「トリガーによってデータベース順序から割り当てられた主キー値の取得方法」を参照)が前提となります。この設定により、アプリケーション・スキーマの表の順序から割り当てられたトリガーの値が、対応するデータベース表から反映されるように属性値がリフレッシュされます。
エンティティ行を作成するには:
エンティティ定義を検索します。
createProduct()メソッドでは、getDefinitionObject()メソッドを使用して、Productエンティティのエンティティ定義を検索します。
新しいインスタンスを作成します。
createProduct()メソッドでは、エンティティ定義に対してcreateInstance2()メソッドを使用して、エンティティ・オブジェクトの新しいインスタンスを作成します。
|
注意: このメソッド名の末尾には2があります。正規のcreateInstance()メソッドにはprotectedアクセス権があり、付録E「ADFビジネス・コンポーネントのよく使用されるメソッド」のE.2.4項「EntityImplクラス」で説明するように、カスタマイズされるように設計されています。AttributeList型の2番目の引数は、作成時に指定する必要がある属性の指定に使用し、リストに検出されたすべての属性の値の初期化に使用するものではありません。たとえば、このAPIを使用して構成される側の子エンティティ行の新しいインスタンスを作成する場合、構成する側の親エンティティの外部キー属性を2番目の引数としてAttributeListオブジェクトに指定します。これを指定しない場合、InvalidOwnerExceptionが発生します。 |
属性値を設定します。
createProduct()メソッドでは、エンティティ・オブジェクトに対して属性のsetterメソッドを使用して、新しいエンティティ行にNameやStatusなどの属性の値を割り当てます。
トランザクションをコミットします。
createProduct()メソッドでは、現在のトランザクション・オブジェクトに対してcommit()をコールし、トランザクションをコミットします。
トリガーによって割り当てられた製品IDをコール元に戻します。
createProduct()メソッドでは、属性のgetterメソッドを使用してProductId属性の値をDBSequenceとして取得し、さらにgetSequenceNumber().longValue()をコールして、順序番号をlong値としてコール元に戻します。
例4-16 エンティティ行の新規作成
/* Create a new Product and Return its new id */
public long createProduct(String name, String status, String shipCode) {
//1. Find the entity definition for the Product entity
EntityDefImpl productDef = ProductBaseEOImpl.getDefinitionObject();
//2. Create a new instance of a Product entity
ProductBaseEOImpl newProduct = (ProductBaseEOImpl)productDef.createInstance2(getDBTransaction(),null);
//3. Set attribute values
newProduct.setProductName(name);
newProduct.setProductStatus(status);
newProduct.setShippingClassCode(shipCode);
newProduct.setSupplierId(new Number(100));
newProduct.setListPrice(new Number(499));
newProduct.setMinPrice(new Number(479));
newProduct.setCreatedBy("Test Client");
newProduct.setLastUpdatedBy("Test Client");
newProduct.setCategoryId(new Number(5));
//4. Commit the transaction
try {
getDBTransaction().commit();
}
catch (JboException ex) {
getDBTransaction().rollback();
throw ex;
}
//5. Access the database-trigger-assigned ProductId value and return it
DBSequence newIdAssigned = newProduct.getProductId();
return newIdAssigned.getSequenceNumber().longValue();
}
新規行を作成する場合、トリガーにより割り当てられた値を使用する(4.10.10項「トリガーによってデータベース順序から割り当てられた主キー値の取得方法」を参照)かわりに、Oracle順序を使用して値を主キーに割り当てることができます。このメタデータ駆動型の方法を使用すると、主キーを取得するためのコードの管理を、複数のエンティティ・オブジェクトにより再使用可能なJavaファイルに一元化できます。
例4-17に、エンティティ・オブジェクトが基づくCustomEntityImplという簡単なフレームワーク拡張クラスを示します。このクラスのオーバーライドされたcreate()メソッドにより、SequenceNameという名前のカスタム属性レベルのメタデータ・プロパティが存在するかどうかがテストされ、検出された場合は、その順序内の次の番号から属性のデフォルト値が移入されます。
例4-17 CustomEntityImplフレームワーク拡張クラス
package sample;
import oracle.jbo.AttributeDef;
import oracle.jbo.AttributeList;
import oracle.jbo.server.EntityImpl;
import oracle.jbo.server.SequenceImpl;
public class CustomEntityImpl extends EntityImpl {
protected void create(AttributeList attributeList) {
super.create(attributeList);
for (AttributeDef def : getEntityDef().getAttributeDefs()) {
String sequenceName = (String)def.getProperty("SequenceName");
if (sequenceName != null) {
SequenceImpl s = new SequenceImpl(sequenceName,getDBTransaction());
setAttribute(def.getIndex(),s.getSequenceNumber());
}
}
}
}
Oracle順序を使用して主キー値を割り当てるには:
プロジェクト内にCustomEntityImpl.javaファイルを作成し、例4-17のコードを挿入します。
「アプリケーション・ナビゲータ」で、編集するエンティティをダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックし、編集する属性をダブルクリックします。
「属性の編集」ダイアログで、「属性」の「型」を「Number」に設定し、「カスタム・プロパティ」ノードをクリックします。
名前としてSequenceNameと入力します。
値に対するデータベース順序の名前を入力して、「追加」をクリックし、さらに「OK」をクリックしてカスタム・プロパティを作成します。
たとえば、Deptエンティティでは、DEPT_TABLE_SEQという値を持つDeptno属性に対して、カスタム・プロパティSequenceNameを定義できます。
エンティティ・オブジェクト・クラスで実装するカスタム・メソッドは、アプリケーション・モジュールの戻り型に依存できません。実行時には、ある場合、そのような依存性を持って実行されるメソッドがClassCastExceptionをスローすることがあります。戻されたアプリケーション・モジュールが、期待された型と一致しないからです。そのため、実装するカスタム・メソッドには、次に示すように、特定のアプリケーション・モジュールやビュー・オブジェクトの実装を取得するコードを記述しないことをお薦めします。
((MyAM)getTransaction().getRootApplicationModule()).getMyVO
特に、次のシナリオにおいて、上のコードがClassCastExceptionで失敗します。
コード内のエンティティ・オブジェクトが、別のビュー・オブジェクト(メソッドで参照しているビュー・オブジェクト以外)のコンテキストで使用されている場合。アプリケーションでは、複数のビュー・オブジェクト定義が同じエンティティ・オブジェクトにマップされることがあるため、ビュー・オブジェクトへの依存性を持つメソッドが、ADFビジネス・コンポーネント・ランタイムで一貫性を持って実行されることは保証できません。
ルート・アプリケーション・モジュールの下に、手動でアプリケーション・モジュールをネストする場合。この場合、ネストされたアプリケーション・モジュールが同じTransactionオブジェクトを共有するため、前述のコードによって、期待されるアプリケーション・モジュールの型が戻される保証はありません。
ADFビジネス・コンポーネント・フレームワークの実装がリリースを追うごとに変化する場合。たとえば、以前のリリースでは、アプリケーションがADFタスク・フローを使用して定義した宣言トランザクションを制御するために、フレームワークで内部的なルート・アプリケーション・モジュールが作成されていました。
この章でこれまで説明してきたように、エンティティ・オブジェクトのデータベース対話機能および多くの宣言的実行時機能はすべて、カスタムJavaコードを使用せずに実現できます。これらの宣言的機能を超えてエンティティにカスタム・ビジネス・ロジックを実装する必要がある場合、カスタム・コードを必要とするエンティティに対してJava生成を有効化する必要があります。通常、カスタム・エンティティ・オブジェクトおよびエンティティ定義クラスで記述、使用およびオーバーライドする一般的なコードの詳細は、付録E「ADFビジネス・コンポーネントのよく使用されるメソッド」を参照してください。
エンティティ・オブジェクトのカスタムJavaクラスの生成を有効にするには、概要エディタの「Java」ページを使用します。
エンティティ・オブジェクトのカスタムJavaクラスを生成するには:
「アプリケーション・ナビゲータ」で、エンティティをダブルクリックします。
概要エディタで、「Java」ナビゲーション・タブをクリックし、「編集」アイコンをクリックします。
「Javaオプションの選択」ダイアログで、生成するJavaクラスのタイプを選択します。
エンティティ・オブジェクト・クラス - 最も頻繁にカスタマイズします。このクラスは、基礎となるデータベース表の各行を示します。
エンティティ・コレクション・クラス - カスタマイズすることはまれです。
エンティティ定義クラス - カスタマイズする頻度は低くなります。このクラスは、エンティティ行を管理し、その構造を定義する関連クラスを示します。
「OK」をクリックします。
生成するカスタムJavaクラスを1つ以上選択すると、指定したJavaファイルが作成されます。たとえば、fodemo.storefront.entities.OrderEOという名前のエンティティ・オブジェクトの場合、そのカスタムJavaファイルのデフォルト名は、エンティティ・オブジェクト・クラスに対してはOrderEOImpl.java、エンティティ定義クラスに対してはOrderEODefImpl.javaになります。これらのファイルは両方とも、コンポーネントのXMLコンポーネント定義ファイルと同じ./fodemo/storefront/entitiesディレクトリに作成されます。
エンティティ・オブジェクトのJava生成オプションは、概要エディタの「Java」ページに後でアクセスしてもそのまま反映されています。XML定義ファイルの場合と同様、このエディタでどのような変更を行っても、カスタムJavaクラスで生成されたコードは最新の状態に保たれます。後でなんらかの理由によりカスタムJavaファイルが必要なくなった場合は、「Java」ページで関連するオプションを無効にすると、カスタムJavaファイルを削除できます。
カスタム・エンティティ・オブジェクト・クラスの生成を有効にする場合、「アクセッサ」オプションも有効にすると、エンティティ・オブジェクトの属性ごとにgetterメソッドおよびsetterメソッドが生成されます。たとえば、OrderEOエンティティ・オブジェクトには、対応するカスタム・クラスOrderEOImpl.javaがあり、(例4-18に示すような)メソッドが生成されます。
例4-18 OrderEOImpl.javaのgetterメソッドとsetterメソッド
public DBSequence getOrderId() { ... }
public void setOrderId(DBSequence value) { ... }
public Date getOrderDate() { ... }
public void setOrderDate(Date value) { ... }
public String getOrderStatusCode() { ... }
public void setOrderStatusCode(String value) { ... }
public Number getCustomerId() { ... }
public void setCustomerId(Number value) { ... }
public String getShipToName() { ... }
public void setShipToName(String value) { ... }
これらのメソッドを使用して行データを操作すると、コンパイル時にデータ型の使用方法が正しいかどうかがチェックされます。つまり、CustomerId属性の値を取得するために次のようなコードを記述するかわりに、
Number customerId = (Number)order.getAttribute("CustomerId");
次のようなコードを記述できます。
Number customerId = order.getCustomerId();
後者の方法では、CustomerIdではなく誤ってCustomerIdentifierと入力したときにJavaコンパイラによって入力ミスが捕捉されます。
// spelling name wrong gives compile error Number customerId = order.getCustomerCode();
エンティティ・オブジェクトのアクセッサ・メソッドが生成されていない場合、次のような不適切なコード行をコンパイラで捕捉できません。
// Both attribute name and type cast are wrong, but compiler cannot catch it
String customerId = (String)order.getAttribute("CustomerCode");
これには、スペルが正しくない属性名とキャストの型が誤っている戻り値getAttribute()が両方とも含まれています。EntityImplベース・クラスが実装するRowインタフェース上で汎用APIを使用する場合、このようなエラーはコンパイル時に捕捉されないため、実行時に例外が発生します。
図4-14のように、カスタムJavaクラスの生成を有効にした場合、これらは、エンティティ・オブジェクトの「アプリケーション・ソース」ノードの下にも子ノードとして表示されます。すべてのADFコンポーネントと同様、アプリケーション・ナビゲータでエンティティ・オブジェクトを選択すると、「構造」ウィンドウには、エンティティの構造ビューが表示されます。カスタムJavaファイルのソース・コードを表示または操作する必要がある場合、ソース・エディタでこのファイルを開く方法には2通りあります。
図4-14のように、Javaファイルを右クリックし、ポップアップ・メニューから「開く」を選択します。
「構造」ウィンドウのノード内の項目を右クリックし、ポップアップ・メニューから「ソースへ移動」を選択します。
カスタムJavaクラスの詳細は、次の各項を参照してください。
XML専用エンティティ・オブジェクトを使用する場合、実行時には、その機能はデフォルトのADFビジネス・コンポーネント実装クラスによって提供されます。生成される各カスタムJavaクラスによって適切なADFビジネス・コンポーネントのベース・クラスが自動的に拡張されるため、コードでは、デフォルトの動作を継承し、このクラスを簡単に追加またはカスタマイズできます。エンティティ・オブジェクト・クラスはEntityImplを拡張し、エンティティ定義クラスはEntityDefImplを拡張します(これらは両方ともoracle.jbo.serverパッケージ内にあります)。
開発者によっては、生成されたJavaソース・ファイルに独自のコードを追加することを躊躇する場合があります。JDeveloperによって作成および管理される各カスタムJavaソース・コード・ファイルには、独自のカスタム・コードをこのファイルに追加しても安全であることを示す、次のようなコメントがファイルの上部に記載されています。
// --------------------------------------------------------------------- // --- File generated by Oracle ADF Business Components Design Time. // --- Custom code may be added to this class. // --- Warning: Do not modify method signatures of generated methods. // ---------------------------------------------------------------------
「編集」ダイアログで「OK」または「適用」ボタンをクリックしても、ファイルが知らぬ間に再生成されることはありません。かわりに、管理が必要なメソッドはスマートに更新され、独自のカスタム・コードはそのまま残されます。
ビュー・オブジェクトの実行時動作をカスタマイズする必要がある場合や、バインド変数またはビュー行属性へ強く型付けされたアクセスのみ行う場合、ビュー・オブジェクトのカスタムJavaクラスを生成できます。
ADF Business ComponentsのカスタムJava生成のデフォルト設定を構成するには、「ツール」メニューから「設定」を選択して、「ビジネス・コンポーネント」ページを開き、後で作成するビジネス・コンポーネントで使用する設定を設定します。ADFビジネス・コンポーネントを初めて使用する開発者には、デフォルトではカスタムJavaクラスを生成しないよう設定することをお薦めします。カスタムJavaコードが必要な状況になった場合、そのコンポーネントに必要なカスタムJavaコードのみを有効にできます。経験を積むにつれ、どのようなデフォルト設定の組合せが最適であるかがわかるようになります。
エンティティ・オブジェクトは、XML専用のエンティティ・オブジェクト、またはカスタムJavaクラスと組み合せたXMLコンポーネント定義に基づいて機能するように設計されています。このどちらとして使用するかを選択できるように、属性値はエンティティのクラス(XML専用モードでは存在しないファイル)のプライベート・メンバー・フィールドには格納されません。かわりに、属性には、名前のみならず、エンティティのXMLコンポーネント定義ファイル内の<Attribute>およびアソシエーション関連の<AccessorAttribute>タグのゼロベースの順序に基づいて、このファイルの数値索引も割り当てられます。実行時には、エンティティ行の属性値は、エンティティの属性リスト内における属性の数値的位置による索引が付けられた状態で、EntityImplベース・クラスによって管理される疎配列構造に格納されます。
多くの場合、このプライベート実装に関する詳細は、エンティティ・オブジェクトを使用する開発者は理解する必要がないため、重要ではありません。ただし、エンティティ・オブジェクトのカスタムJavaクラスを有効にする場合、エンティティ・オブジェクト・クラスで管理される生成コードの一部にこの実装の詳細が関わってきます。この場合、コードの使用目的を理解している方が賢明です。たとえば、OrderEOエンティティ・オブジェクトのカスタムJavaクラスの場合、属性またはアクセッサ属性ごとに対応する生成済の整数定数があります。JDeveloperでは、これらの定数の値がXMLコンポーネント定義内の属性の順序を正しく反映しているかどうかが確認されます。
また、自動的に管理される、エンティティ・オブジェクト・クラスで強く型付けされたgetterメソッドおよびsetterメソッドでは、これらの属性定数は例4-19のように使用されます。
例4-19 カスタム・エンティティJavaクラスの属性定数を使用するgetterメソッドとsetterメソッド
// In oracle.fodemo.storefront.entities.OrderEOImpl class
public Date getOrderDate() {
return (Date)getAttributeInternal(ORDERDATE); // <-- Attribute enum
}
public void setOrderDate(Date value) {
setAttributeInternal(ORDERDATE, value); // <-- Attribute enum
}
エンティティ属性定数に関連する自動管理コードのもう1つの側面は、getAttrInvokeAccessor()およびsetAttrInvokeAccessor()メソッドです。これらのメソッドにより、数値索引を使用した属性アクセスのパフォーマンスが最適化され、汎用処理の実行時にEntityImplベース・クラスの汎用コードが属性値にアクセスするときの通常のパフォーマンスと同じになります。getAttrInvokeAccessor()メソッドの例を例4-20に示します。もう1つのsetAttrInvokeAccessor()メソッドの場合も同様です。
例4-20 カスタム・エンティティJavaクラスのgetAttrInvokeAccessor()メソッド
// In oracle.fodemo.storefront.entities.OrderEOImpl class
/** getAttrInvokeAccessor: generated method. Do not modify. */
protected Object getAttrInvokeAccessor(int index, AttributeDefImpl attrDef)
throws Exception {
if ((index >= AttributesEnum.firstIndex()) && (index < AttributesEnum.count())) {
return AttributesEnum.staticValues()[index - AttributesEnum.firstIndex()].get(this);
}
return super.getAttrInvokeAccessor(index, attrDef);
}
属性と索引に関連して生成されたこのコードに関する経験則は、次のとおりです。
必要に応じて、強く型付けされた属性のgetterメソッドおよびsetterメソッドの内部にカスタム・コードを追加してください。
概要エディタを使用して、エンティティ・オブジェクト属性の順序または型を変更してください。
getterメソッドおよびsetterメソッドのJavaシグネチャや関連するXMLコンポーネント定義は、自動的に変更されます。
getAttrInvokeAccessor()メソッドおよびsetAttrInvokeAccessor()メソッドは変更しないでください。
属性索引番号の値は手動で変更しないでください。
|
注意: ソース・コントロールのマージ競合やその他の理由により、生成された属性定数を手動で編集する必要がある場合、対応するエンティティ・オブジェクトのXMLコンポーネント定義の<Attribute>および<AccessorAttribute>タグの順序がゼロベースの順序に反映されていることを確認する必要があります。 |
生成したカスタム・エンティティ・クラスを使用する場合とEntityImpl汎用クラスを使用する場合の違いをよりわかりやすくするため、例4-21に、カスタム・アプリケーション・モジュール・クラス(StoreFrontService2Impl.java)の、カスタム・エンティティ・クラス(StoreFrontServiceImpl.java)のメソッドのバージョンを示します。重要な違いは、次のとおりです。
属性アクセスは、強く型付けされた属性アクセッサを使用して実行されます。
アソシエーションのアクセッサ属性により、アソシエーションの反対側にある強く型付けされたエンティティ・クラスが戻されます。
カスタム・エンティティ・クラスのgetDefinitionObject()メソッドを使用すると、完全修飾されたエンティティ定義名を文字列として使用しないようにできます。
カスタム・エンティティ・クラスのcreatePrimaryKey()メソッドにより、エンティティのKeyオブジェクトの作成を簡略化します。
例4-21 強く型付けされたカスタム・エンティティ・オブジェクト・クラスを使用したプログラム的なエンティティの例
package devguide.examples.appmodules;
import oracle.fodemo.storefront.entities.OrderEOImpl;
import oracle.fodemo.storefront.entities.PersonEOImpl;
import oracle.fodemo.storefront.entities.ProductBaseEOImpl;
import oracle.jbo.ApplicationModule;
import oracle.jbo.JboException;
import oracle.jbo.Key;
import oracle.jbo.client.Configuration;
import oracle.jbo.domain.DBSequence;
import oracle.jbo.domain.Number;
import oracle.jbo.server.ApplicationModuleImpl;
import oracle.jbo.server.EntityDefImpl;
// ---------------------------------------------------------------------
// --- File generated by Oracle ADF Business Components Design Time.
// --- Custom code may be added to this class.
// --- Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
/**
* This custom application module class illustrates the same
* example methods as StoreFrontServiceImpl.java, except that here
* we're using the strongly typed custom Entity Java classes
* OrderEOImpl, PersonsEOImpl, and ProductsBaseEOImpl instead of working
* with all the entity objects using the base EntityImpl class.
*/
public class StoreFrontService2Impl extends ApplicationModuleImpl {
/**This is the default constructor (do not remove).
*/
public StoreFrontService2Impl() {
}
/*
* Helper method to return an Order by Id
*/
private OrderEOImpl retrieveOrderById(long orderId) {
EntityDefImpl orderDef = OrderEOImpl.getDefinitionObject();
Key orderKey = OrderEOImpl.createPrimaryKey(new DBSequence(orderId));
return (OrderEOImpl)orderDef.findByPrimaryKey(getDBTransaction(),orderKey);
}
/*
* Find an Order by Id
*/
public String findOrderTotal(long orderId) {
OrderEOImpl order = retrieveOrderById(orderId);
if (order != null) {
return order.getOrderTotal().toString();
}
return null;
}
/*
* Create a new Product and Return its new id
*/
public long createProduct(String name, String status, String shipCode) {
EntityDefImpl productDef = ProductBaseEOImpl.getDefinitionObject();
ProductBaseEOImpl newProduct = (ProductBaseEOImpl)productDef.createInstance2(getDBTransaction(),null);
newProduct.setProductName(name);
newProduct.setProductStatus(status);
newProduct.setShippingClassCode(shipCode);
newProduct.setSupplierId(new Number(100));
newProduct.setListPrice(new Number(499));
newProduct.setMinPrice(new Number(479));
newProduct.setCreatedBy("Test Client");
newProduct.setLastUpdatedBy("Test Client");
newProduct.setCategoryId(new Number(5));
try {
getDBTransaction().commit();
}
catch (JboException ex) {
getDBTransaction().rollback();
throw ex;
}
DBSequence newIdAssigned = newProduct.getProductId();
return newIdAssigned.getSequenceNumber().longValue();
}
/*
* Update the status of an existing order
*/
public void updateRequestStatus(long orderId, String newStatus) {
OrderEOImpl order = retrieveOrderById(orderId);
if (order != null) {
order.setOrderStatusCode(newStatus);
try {
getDBTransaction().commit();
}
catch (JboException ex) {
getDBTransaction().rollback();
throw ex;
}
}
}
/*
* Access an associated Customer entity from the Order entity
*/
public String findOrderCustomer(long orderId) {
OrderEOImpl svcReq = retrieveOrderById(orderId);
if (svcReq != null) {
PersonEOImpl cust = (PersonEOImpl)svcReq.getPerson();
if (cust != null) {
return cust.getFirstName() + " " + cust.getLastName();
}
else {
return "Unassigned";
}
}
else {
return null;
}
}
/*
* Testing method
*/
public static void main(String[] args) {
String amDef = "devguide.model.StoreFrontService";
String config = "StoreFrontServiceLocal";
ApplicationModule am = Configuration.createRootApplicationModule(amDef,config);
/*
* NOTE: This cast to use the StoreFrontServiceImpl class is OK since
* this code is inside a business tier *Impl.java file and not in a
* client class that is accessing the business tier from "outside".
*/
StoreFrontServiceImpl service = (StoreFrontServiceImpl)am;
String total = service.findOrderTotal(1011);
System.out.println("Status of Order # 1011 = " + total);
String customerName = service.findOrderCustomer(1011);
System.out.println("Customer for Order # 1011 = " + customerName);
try {
service.updateOrderStatus(1011,"CANCEL");
}
catch (JboException ex) {
System.out.println("ERROR: "+ex.getMessage());
}
long id = 0;
try {
id = service.createProduct(null, "NEW", "CLASS1");
}
catch (JboException ex) {
System.out.println("ERROR: "+ex.getMessage());
}
id = service.createProduct("Canon PowerShot G9", "NEW", "CLASS1");
System.out.println("New product created successfully with id = "+id);
Configuration.releaseRootApplicationModule(am,true);
}
}
基礎となる表内の列にマップされる属性のみでなく、エンティティ・オブジェクトには、値ホルダーである一時属性や(JavaやGroovyなどを使用して)計算された値を表示する一時属性を組み込むことができます。たとえば、FullNameなどの作成した一時属性は、FirstName属性の値とLastName属性の値を連結した値に基づいて計算できます。
一時属性を作成すると、エンティティ・オブジェクトのJavaクラスで計算を実行したり、属性定義でGroovy式を使用してデフォルト値を指定できます。
実行時に値を変更できるようにする必要がある場合は、Groovy式を使用します。計算された後に変更される可能性が低い値(明細項目の合計など)については、エンティティ・オブジェクトのJavaクラス内で直接計算できます。
一時属性を作成するには、概要エディタの「属性」ページを使用します。
エンティティ・オブジェクトに一時属性を追加するには:
「アプリケーション・ナビゲータ」で、エンティティをダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックし、「新規」アイコンをクリックします。
属性の名前を入力します。
Javaの属性の型を設定します。
「永続的」オプションを無効にします。
値を計算する場合、「更新可能」を「なし」に設定します。
「OK」をクリックします。
一時属性を追加すると、エンティティ・オブジェクトのXMLコンポーネント定義が更新され、新しい属性が反映されます。
例4-22に示すように、一時属性の<Attribute>タグには、TableNameはなく、ColumnNameが$none$になっています。
例4-22 一時属性のXMLコード
<Attribute Name="FullName" IsUpdateable="false" IsQueriable="false" IsPersistent="false" ColumnName="$none$" Type="java.lang.String" ColumnType="$none$" SQLType="VARCHAR" > </Attribute>
これに対し、永続的エンティティ属性には、例4-23のようにTableNameとColumnNameの両方があります。
一時属性を作成する場合、デフォルト値の指定にGroovy式を使用できます。
Groovy式に基づいて一時属性を作成するには:
4.14.1項「一時属性の追加方法」の最初の4ステップに従って、新しい属性を作成します。
「アプリケーション・ナビゲータ」で、エンティティをダブルクリックします。
概要エディタで、「属性」ナビゲーション・タブをクリックし、「新規」アイコンをクリックします。
「新規エンティティ属性」ダイアログで、属性の名前を入力します。
Javaの属性の型を設定します。
「値」フィールド隣の「編集」ボタンをクリックします。
定義した式は、Groovyスクリプト言語を使用して評価されます(3.6項「Groovyサポートの概要」を参照)。Groovyを使用すると、式や変数を文字列に挿入できます。この式は、エンティティ・オブジェクト定義の一部として保存されます。
図4-15に示すように、「式の編集」ダイアログで、表示されているフィールドに式を入力します。
参照する属性には、エンティティ・オブジェクトで定義されている任意の属性を使用できます。式にある属性のうち、エンティティ・オブジェクトで定義されていない属性は参照しないでください。
適切な再計算設定を選択します。
「常に」(デフォルト)を選択すると、行のいずれかの属性が変更されるたびに式の評価が行われます。「なし」を選択すると、行が作成された場合にのみ式の評価が行われます。
必要に応じて、式の再計算を実行するタイミングの条件を指定できます。
たとえば、「次の式に基づく」フィールドに次のような式を入力すると、Quantity属性またはUnitPrice属性が変更された場合に属性が再計算されます。
return (adf.object.isAttributeChanged("Quantity") || adf.object.isAttributeChanged("UnitPrice"));
この属性が依存する属性もリストできます。
図4-15では、QuantityおよびUnitPrice属性が選択されているので、いずれかの属性が変更されると属性は再計算されます。
「OK」をクリックして、式を保存します。
次に、「OK」をクリックし、属性を作成します。
|
注意: 定義した値式またはオプションの再計算式がベース・エンティティ・オブジェクトの属性を参照する場合は、「属性の編集」ダイアログの「依存性」ページでこれを依存性として定義する必要があります。「依存性」ページで、「使用可能」リストで属性を特定し、それぞれを「選択済」リストに移動します。 |
一時属性がGroovy式に準拠している場合は、例4-24に示すように<TransientExpression>タグがエンティティ・オブジェクトのXMLファイルの適切な属性内に追加されます。
一時属性は、データ値のプレースホルダです。一時属性の「更新可能」プロパティを「新規の間」または「常に」に変更すると、エンド・ユーザーは属性値を入力できるようになります。一時属性に計算値を表示する場合は通常、「更新可能」プロパティを「なし」に設定し、値を計算するカスタムJavaコードを記述します。
エンティティ・オブジェクトに一時属性を追加した後、この属性計算属性にするには、次のようにする必要があります。
概要エディタの「Java」ページでカスタム・エンティティ・オブジェクト・クラスを有効にし、アクセッサ・メソッドの生成を選択します。
一時属性のアクセッサ・メソッドの内部で、計算済値を戻すJavaコードを記述します。
「属性の編集」ダイアログの「依存性」ページで、一時属性の依存属性をそれぞれ指定します。
たとえば、ビュー行クラスを生成した後、一時属性の計算値を戻すJavaコードは、例4-25のように属性のgetterメソッド(FullNameなど)にあります。
例4-25 一時属性のgetterメソッド
// Getter method for FullName calculated attribute in UserImpl.java
public String getFullName() {
// Commented out original line since we'll always calculate the value
// return (String)getAttributeInternal(FULLNAME);
return getFirstName()+" "+getLastName();
}
エンド・ユーザーによって、連結される属性(LastNameやFirstNameなど)が変更されるたびに、一時属性が再評価されるようにするには、一時属性の依存属性を指定します。「属性の編集」ダイアログの「依存性」ページで、「使用可能」リストで属性を特定し、それぞれを「選択済」リストに移動します。