この章では、リレーショナル・ディスクリプタの構成方法について説明します。
この章の内容は次のとおりです。
複数のディスクリプタ・タイプに共通のディスクリプタのオプションを構成する方法の詳細は、第119章「ディスクリプタの構成」を参照してください。
表23-1は、リレーショナル・ディスクリプタに構成可能なデフォルトのオプションを示します。
表23-1は、リレーショナル・ディスクリプタに構成可能なデフォルトのオプションを示します。
表23-1 リレーショナル・ディスクリプタの構成可能オプション
詳細は、第21章「リレーショナル・ディスクリプタの概要」を参照してください。
各リレーショナル・クラス・ディスクリプタ(22.2.1.1項「リレーショナル・クラス・ディスクリプタの作成」を参照)は、そのクラスのインスタンスを格納するためのデータベース表に関連付ける必要があります。これは、リレーショナル集約ディスクリプタには適用されません(22.2.1.2項「リレーショナル集約ディスクリプタの作成」を参照)。
データベース表にディスクリプタを関連付けるには、次の手順を実行します。
「関連表」のリストから、ディスクリプタに関連付けるデータベース表を選択します。ディスクリプタとデータベース表の関連付けは、主キーを指定する前に行う必要があります。
Javaを使用してディスクリプタの関連表を構成するには、RelationalDescriptor
のメソッドsetTableName
またはaddTableName
を使用します。
順序付けを使用すると、オブジェクトの挿入時に、そのオブジェクトの主キーまたはIDを自動的に割り当てることができます。
TopLinkの順序付け機能をプロジェクト・レベル(20.3項「プロジェクト・レベルでの順序付けの構成」を参照)またはセッション・レベル(98.4項「セッション・レベルでの順序付けの構成」を参照)で構成することによって、順序値を取得する方法、つまり使用する順序タイプをTopLinkに指示します。
順序付けを有効化するには、ディスクリプタ・レベルでTopLinkの順序付けを構成し、ディスクリプタの参照クラスのインスタンスが作成される際に順序値を書き込む表および列をTopLinkに指示します。
順序フィールドと順序名が構成されたディスクリプタにのみ、順序番号が割り当てられます。
順序フィールドとは、順序番号が割り当てられるデータベース・フィールドで、ほとんどの場合、主キー・フィールドがこれになります(119.2項「主キーの構成」を参照)。順序名とは、そのディスクリプタに使用する順序の名前です。順序名の意味は、次に示すとおり、使用する順序付けのタイプによって異なります。
表による順序付けを使用する場合、順序名は順序を格納する行のSEQ_NAMEの値を参照します。
Oracleのネイティブ順序付けを使用する場合、順序名はデータベース内に作成されているOracle順序オブジェクトを参照します。他のデータベースのネイティブ順序付けを使用する場合、順序名はそれ自体としては意味を持ちませんが、互換性確保のため必ず設定してください。
順序名には、プロジェクトに定義するカスタムの順序名を参照させることもできます。
詳細は、18.2項「リレーショナル・プロジェクトにおける順序付け」を参照してください。
ディスクリプタに順序付けを構成するには、次の手順を実行します。
次の情報を参照し、順序付けの各オプションを指定します。
フィールド | 説明 |
---|---|
順序付けの使用 | このディスクリプタに順序付けを使用する場合に選択します。このオプションを選択した場合は、順序付けの「名前」、「表」および「フィールド」に値を指定します。 |
名前 | 順序の名前を指定します。
|
表 | このディスクリプタの参照クラスの新規インスタンスが作成される際にTopLinkによって順序値が書き込まれるフィールド(「フィールド」を参照)のあるデータベース表の名前を指定します。通常は、ディスクリプタのプライマリ表の名前です。 |
フィールド | このディスクリプタの参照クラスの新規インスタンスが作成される際にTopLinkで順序値を書き込むように指定した表(「表」を参照)の、フィールドの名前を指定します。通常、このフィールドにはクラスの主キーを指定します(119.2項「主キーの構成」を参照)。
|
Javaを使用すると、様々なディスクリプタに対して、タイプの異なる複数の順序を使用した順序付けを構成できます。セッションのログイン・オブジェクトに順序オブジェクトを構成し、その順序オブジェクトをディスクリプタから名前によって参照します。ディスクリプタの順序名は、セッションのログイン・オブジェクトに登録された順序オブジェクト名を参照します。
次に示す各例は、セッションに例23-1の順序が構成されていることを前提としています。
例23-1 順序の例
dbLogin.addSequence(new TableSequence("EMP_SEQ", 25)); dbLogin.addSequence(new DefaultSequence("PHONE_SEQ", 30)); dbLogin.addSequence(new UnaryTableSequence("ADD_SEQ", 55)); dbLogin.addSequence(new NativeSequence("NAT_SEQ", 10));
Javaコードを使用すると、次の順序構成を行えます。
例23-2のように、順序名を使用して順序とディスクリプタを関連付けます。順序EMP_SEQ
は、例23-1でこのプロジェクトのログイン・オブジェクトに追加済です。Employee
クラスの新規インスタンスが作成されると、TopLinkランタイムではEMP_SEQ
という順序(この例ではTableSequence
)を使用してEMP_ID
フィールドの値が取得されます。
例23-3のように、複数のディスクリプタに同一の順序を関連付けることができます。この例では、Employee
ディスクリプタとPhone
ディスクリプタが同一のNativeSequence
を使用しています。複数のディスクリプタに同一の順序を共有させると、事前割当てのパフォーマンスが向上します。事前割当ての詳細は、18.2.3項「順序付けと事前割当てサイズ」を参照してください。
例23-4では、存在しない順序(NEW_SEQ
)をディスクリプタに関連付けています。例23-1でこのプロジェクトのログインにNEW_SEQ
という順序を追加していないため、TopLinkランタイムでこのディスクリプタ用にNEW_SEQ
というDefaultSequence
が作成されます。DefaultSequence
の詳細は、18.2.2.4項「デフォルトの順序付け」を参照してください。
TopLinkを使用して、基本的な永続データ操作(挿入、更新、削除、読取り、すべて読取り、存在チェック)ごとに1つのSQL問合せを定義できます。これにより、リレーショナル・マップ・オブジェクトに問い合せてそれを変更する際に、TopLinkランタイムではデフォルトのSQL問合せのかわりに適切なSQL問合せが使用されます。
SQL文字列には、引数および、ディスクリプタがマップする任意のフィールドを含めることができます。SQL文字列に引数を指定するには、#<arg-name>
の形式で次のように入力します。
select * from EMP where EMP_ID = #EMP_ID
挿入および更新用のSQL文字列は、ディスクリプタがマップする任意のフィールドを引数としてとることができます。
読取り、削除および存在チェック用のSQL文字列は、主キー・フィールドのみを引数としてとることができます。
すべて読取り用のSQL文字列は、クラスの全インスタンスを返す必要があるため、引数をとることはできません。
Javaを使用した場合には、挿入、更新、削除、読取り、すべて読取り、存在チェック用に、カスタムSQL文字列を定義できます(23.4.1項「TopLink Workbenchを使用した基本的な永続データ操作用のカスタムSQL問合せの構成方法」を参照)。
Javaを使用した場合には、挿入、更新、削除、読取り、すべて読取り、存在チェック用に、カスタムSQL文字列またはCall
オブジェクトを定義できます(23.4.2項「Javaを使用した基本的な永続データ操作用のカスタムSQL問合せの構成方法」を参照)。Call
を使用すると、より複雑なSQL文字列の定義や、カスタムのストアド・プロシージャの起動ができます。
CMPプロジェクトの場合は、問合せリストはejb-jar.xml
ファイルに格納されます。問合せは、このファイル内で定義してからOracle JDeveloperまたはTopLink Workbenchに読み取ることも、TopLink Workbenchの「問合せ」タブで定義してからこのファイルに書き込むこともできます(19.7項「ejb-jar.xmlファイルの使用」を参照)。
注意: オプティミスティック・ロック(119.26項「ロック・ポリシーの構成」を参照)を使用するアプリケーションの永続データ更新操作をカスタマイズする際には、最初のオブジェクトの読取り後に行のバージョン・フィールドが変更された場合に、カスタム更新文字列がそのオブジェクトを書き込まないようにする必要があります。さらに、オブジェクトを正常に書き込んだ場合は、バージョン・フィールドを増分する必要があります。次に例を示します。 update Employee set F_NAME = #F_NAME, VERSION = VERSION + 1 where (EMP_ID = #EMP_ID) AND (VERSION = #VERSION) また、更新文字列はデータベースの行カウントを維持する必要があります。 |
注意: TopLinkでは、入力したSQLコードは検証されません。使用するデータベース・プラットフォームに適したSQLコードを入力してください(96.1.3項「データ・ソース・プラットフォームのタイプ」を参照)。 |
基本的な永続データ操作のカスタムSQL問合せを構成するには、次の手順を実行します。
適切なSQL関数タブをクリックして、ディスクリプタに対するこれらのアクションを制御するための独自のSQLを入力します。次の情報を参照し、タブに指定を行います。
DescriptorQueryManager
では、次の永続データ操作用のデフォルトSQLが生成されます。
挿入
更新
削除
読取り
すべて読取り
存在チェック
Javaコードにより、ディスクリプタ問合せマネージャを使用して、これらの関数をクラス単位で実行するためのカスタムSQL文字列を提供できます。
そのためには、ClassDescriptor
メソッドgetQueryManager
を使用してDescriptorQueryManager
を取得し、表23-2に示すDescriptorQueryManager
の各メソッドを使用します。
表23-2 カスタムSQLを構成するためのディスクリプタ問合せマネージャ・メソッド
デフォルトSQLを変更する対象操作 | 使用するディスクリプタ問合せマネージャ・メソッド |
---|---|
挿入 |
|
|
|
|
|
更新 |
|
|
|
|
|
削除 |
|
|
|
|
|
読取り |
|
|
|
|
|
すべて読取り |
|
|
|
|
|
存在チェック |
|
|
|
|
例23-5は、修正メソッドを実装し、カスタムSQL文字列を使用するようにディスクリプタ問合せマネージャを構成する方法を示します。また、別の方法として、SQLCall
を使用して、入力、出力および入出力パラメータやパラメータ・タイプなどの機能によって複雑なSQL文字列を指定することもできます(109.4項「SQLCallの使用」を参照)。
例23-5 カスタムSQL文字列を使用したディスクリプタ問合せマネージャの構成
public static void addToDescriptor(ClassDescriptor descriptor) { // Read-object by primary key procedure descriptor.getQueryManager().setReadObjectSQLString( "select * from EMP where EMP_ID = #EMP_ID"); // Read-all instances procedure descriptor.getQueryManager().setReadAllSQLString( "select * from EMP"); // Insert procedure descriptor.getQueryManager().setInsertSQLString( "insert into EMP (EMP_ID, F_NAME, L_NAME, MGR_ID) values (#EMP_ID, #F_NAME, #L_NAME, #MGR_ID)"); // Update procedure descriptor.getQueryManager().setUpdateSQLString( "update EMP set (F_NAME, L_NAME, MGR_ID) values (#F_NAME, #L_NAME, #MGR_ID) where EMP_ID = #EMP_ID"); }
例23-6は、修正メソッドを実装し、StoredProcedureCall
(109.5項「StoredProcedureCallの使用」を参照)によってOracleストアド・プロシージャを使用するようにディスクリプタ問合せマネージャを構成する方法を示します。この例では、結果セットを返すために出力カーソルを使用しています(111.11項「カーソルとストリームの問合せ結果の処理」を参照)。
例23-6 カスタムのストアド・プロシージャ・コールを使用したディスクリプタ問合せマネージャの構成
public static void addToDescriptor(ClassDescriptor descriptor) { // Read-object by primary key procedure StoredProcedureCall readCall = new StoredProcedureCall(); readCall.setProcedureName("READ_EMP"); readCall.addNamedArgument("P_EMP_ID", "EMP_ID"); readCall.useNamedCursorOutputAsResultSet("RESULT_CURSOR"); descriptor.getQueryManager().setReadObjectCall(readCall); // Read-all instances procedure StoredProcedureCall readAllCall = new StoredProcedureCall(); readAllCall.setProcedureName("READ_ALL_EMP"); readAllCall.useNamedCursorOutputAsResultSet("RESULT_CURSOR"); descriptor.getQueryManager().setReadAllCall(readAllCall ); // Insert procedure StoredProcedureCall insertCall = new StoredProcedureCall(); insertCall.setProcedureName("INSERT_EMP"); insertCall.addNamedArgument("P_EMP_ID", "EMP_ID"); insertCall.addNamedArgument("P_F_NAME", "F_NAME"); insertCall.addNamedArgument("P_L_NAME", "L_NAME"); insertCall.addNamedArgument("P_MGR_ID", "MGR_ID"); descriptor.getQueryManager().setInsertCall(insertCall); // Update procedure StoredProcedureCall updateCall = new StoredProcedureCall(); updateCall.setProcedureName("UPDATE_EMP"); updateCall.addNamedArgument("P_EMP_ID", "EMP_ID"); updateCall.addNamedArgument("P_F_NAME", "F_NAME"); updateCall.addNamedArgument("P_L_NAME", "L_NAME"); updateCall.addNamedArgument("P_MGR_ID", "MGR_ID"); descriptor.getQueryManager().setUpdateCall(updateCall); }
インタフェース・エイリアスを使用すると、インタフェースを介して実装クラスのかわりにディスクリプタを参照できます。この方法は、クラスにパブリック・インタフェースがあり、アプリケーションがそのパブリック・インタフェースを介してクラスを参照する必要がある場合に便利です。インタフェース・エイリアスを指定することにより、TopLinkセッションで実行される任意の問合せで、実装クラスを使用するかわりにインタフェースを参照クラスとして使用できます。
各ディスクリプタに指定できるインタフェース・エイリアスは1つです。これらのインタフェースは、問合せやリレーションシップ・マッピングに使用します。
注意: インタフェース・エイリアスを使用する場合、インタフェースにはインタフェース・ディスクリプタを関連付けないでください。 |
この項では、インタフェース・エイリアスの構成方法について説明します。インタフェースはOracle JDeveloperまたはTopLink Workbenchでは作成できません。インタフェース・エイリアスを構成するには、JavaパッケージまたはクラスをOracle JDeveloperまたはTopLink Workbenchプロジェクトに追加しておく必要があります。
インタフェース・エイリアスを指定するには、次の手順を実行します。
ナビゲータで、ディスクリプタを選択します。
そのディスクリプタに対して「インタフェース・エイリアス」アドバンスト・プロパティが表示されない場合は、ディスクリプタを右クリックして、コンテキスト・メニューまたは「選択」メニューから「アドバンスト・プロパティの選択」→「インタフェース・エイリアス」を選択します。
「インタフェース・エイリアス」フィールドで、「参照」をクリックしてインタフェースを選択します。
Javaを使用してインタフェース・エイリアスをディスクリプタに構成するには、例23-7のように、ディスクリプタ修正メソッドを作成して(119.35項「修正メソッドの構成」を参照)、InterfacePolicy
メソッドaddParentInterface
を使用します。
デフォルトでは、リレーショナル・プロジェクトにJavaクラスを追加するときに(117.3項「プロジェクト・クラスパスの構成」を参照)、Oracle JDeveloperまたはTopLink WorkbenchによってそのJavaクラス用のリレーショナル・クラス・ディスクリプタが作成されます。クラス・ディスクリプタは、任意の永続オブジェクトに適用できます。ただし、集約リレーションシップにおいて相手オブジェクトに所有されているオブジェクトは除きます。この種のオブジェクトは、集約ディスクリプタを使用して記述する必要があります。クラス・ディスクリプタを使用すると、集約コレクションおよび集約オブジェクト・マッピングを除く任意のリレーショナル・マッピングを構成できます。
集約オブジェクトは、それを所有するオブジェクトに完全に依存するオブジェクトです。集約ディスクリプタでは、表や主キー、または多くの標準のディスクリプタ・オプションは定義しません。これらは、集約ディスクリプタが所有側のディスクリプタから取得するためです。集約マッピングを構成して、ターゲット・オブジェクト内のデータ・メンバーをソース・オブジェクトの基礎となるデータベース表のフィールドに関連付ける場合は(第35章「リレーショナル集約コレクション・マッピングの構成」および第37章「リレーショナル集約オブジェクト・マッピングの構成」を参照)、ターゲット・オブジェクトのディスクリプタを集約として指定する必要があります。
あるいは、リレーショナル・ディスクリプタから集約指定を削除して、デフォルトのタイプに返すこともできます。
集約として定義されたディスクリプタ(119.20項「子(ブランチまたはリーフ)クラス・ディスクリプタに関する継承の構成」を参照)で継承を構成できますが、その場合は継承ツリー内のすべてのディスクリプタが集約である必要があります。集約ディスクリプタとクラス・ディスクリプタは、同じ継承ツリーに置くことはできません。詳細は、16.3.4項「集約およびコンポジット・ディスクリプタと継承」を参照してください。
また、集約として構成したディスクリプタにはEJB情報を構成できません(119.18項「EJB CMPおよびBMP情報によるディスクリプタの構成」を参照)。
詳細は、50.1.1項「XMLディスクリプタと集約」を参照してください。
リレーショナル・ディスクリプタをクラスまたは集約として構成するには、次の手順を実行します。
ナビゲータで、リレーショナル・ディスクリプタを選択します。
マッピング・ツールバーの「クラス」または「集約」ボタンをクリックします。
または、ディスクリプタを選択してメニューから「選択」→「ディスクリプタ・タイプ」→「クラス」または「集約」を選択するか、ナビゲータ・ウィンドウでディスクリプタを右クリックしてコンテキスト・メニューから「ディスクリプタ・タイプ」→「クラス」または「集約」と選択することもできます。
「集約」を選択した場合は、集約ディスクリプタの各属性を「フィールドへ直接マッピング」として指定します。詳細は、第29章「リレーショナル・フィールドへ直接マッピングの構成」を参照してください。
集約ディスクリプタの各属性を「フィールドへ直接マッピング」として指定します。詳細は、第29章「リレーショナル・フィールドへ直接マッピングの構成」を参照してください。
ターゲット・クラスの属性は、集約オブジェクト・マッピングを構成するまではデータ・ソースに直接マップされませんが、マッピング・タイプをターゲット・クラスのディスクリプタに指定することはできます。これは、ソース・オブジェクトのディスクリプタへの集約マッピングの構成時に使用するマッピング・タイプをTopLinkに指示するものです。詳細は、21.2項「リレーショナル・プロジェクトでの集約ディスクリプタとコンポジット・ディスクリプタ」を参照してください。
Javaを使用してリレーショナル・ディスクリプタを集約として構成するには、ClassDescriptor
メソッドdescriptorIsAggregate
を使用します。
リレーショナル・ディスクリプタを集約コレクション・マッピング用に構成するには、ClassDescriptor
メソッドdescriptorIsAggregateCollection
を使用します。
リレーショナル・ディスクリプタを非集約として構成するには、ClassDescriptor
メソッドdescriptorIsNormal
を使用します。
ディスクリプタでは、マッピングで複数の表を使用できます。複数の表は、次のいずれかの条件が満たされる場合に使用します。
サブクラスが継承に含まれ、そのスーパークラスが1つの表にマップされている一方で、そのサブクラスが別の表にマップされている追加属性を持つ場合
クラスが継承に含まれておらず、そのデータが複数の表にまたがっている場合
ディスクリプタに複数の表を指定した場合は、プライマリ表の行を他のすべての表に結合できる必要があります。デフォルトでは、TopLinkは、最初の表つまりプライマリ表の主キーがその他の表に含まれ、このため、他の表を結合できるものと想定しています。また、TopLinkでは表を結合するためのカスタム・メソッドもサポートされています。複数の表の主キー・フィールドの名前が異なる場合は、外部キーを使用して表を結合できます。使用できるのは、プライマリ表からセカンダリ表への外部キー、セカンダリ表からプライマリ表への外部キー、または2つのセカンダリ表間での外部キーです(23.7.1項「TopLink Workbenchを使用した複数表の情報の構成方法」を参照)。
複数表の関係が複雑な場合は、さらに複雑な結合式が必要なことがあります。たとえば、結合でタイプのコードのチェックも必要な場合や、外部結合を使用する場合などです。TopLinkでは、そのような場合に複数表結合式を使用できます(23.7.2項「Javaを使用した複数表の情報の構成方法」を参照)。
1つのディスクリプタに複数の表を関連付けるには、次の手順を実行します。
ナビゲータで、ディスクリプタを選択します。
ディスクリプタの「複数表の情報」アドバンスト・プロパティが表示されない場合は、ディスクリプタを右クリックして、コンテキスト・メニューまたは「選択」メニューから「アドバンスト・プロパティの選択」→「複数表の情報」を選択します。
次の情報を参照し、タブの各フィールドにデータを入力します。
フィールド | 説明 |
---|---|
プライマリ表 | このディスクリプタのプライマリ表です。このフィールドは表示専用です。 |
追加の表 | 「追加」と「削除」を使用して、追加の表を追加または削除できます。 |
プライマリ表へのアソシエーション | 追加の表のそれぞれを次のどの方法でプライマリ表に関連付けるかを指定します。
|
参照による表の関連付け
表への関連付けで「参照」を選択すると、追加のオプションがアクティブになります。選択する参照は、プライマリ表の適切なフィールドと選択した表の主キーとを関連付けるものである必要があります。
「表参照」を選択して、プライマリ表の主キーと選択した表の主キーとの関連付け方法を定義します。「追加」をクリックして、主キーの関連付けを追加します。
Javaを使用してディスクリプタに複数表の情報を構成するには、次のoracle.toplink.descriptors.ClassDescriptor
メソッドを使用します。
addTableName(java.lang.String tableName)
addForeignKeyFieldNameForMultipleTable(java.lang.String sourceForeignKeyFieldName, java.lang.String targetPrimaryKeyFieldName)
複雑な複数表結合式を指定するには、ディスクリプタ修正メソッドを作成し(119.35項「修正メソッドの構成」を参照)、そのメソッドに、oracle.toplink.descriptors.DescriptorQueryManager
メソッドsetMultipleTableJoinExpression
を使用した結合式を追加します。詳細は、111.7項「その他の結合式の追加」を参照してください。