TopLinkでは、ディスクリプタを使用して、あるデータ・ソースによって特定クラスのインスタンスがどのように表現されるかを定義した情報を格納します。ディスクリプタには、クラスのインスタンス変数を、データ・ソースおよび、値の格納と取得に使用されるトランスフォーメーション・ルーチンに関連付けるマッピングを含めます。それによって、ディスクリプタは、Javaオブジェクトとそのデータ・ソース表現を接続する役目を果します。
この章の内容は次のとおりです。
表23-1は、オブジェクト・モデルにクラスを定義するために使用するディスクリプタ・タイプをまとめたものです。それぞれについて、基本タイプか詳細タイプかの分類も示します。
表23-1 TopLinkのディスクリプタ・タイプ
ディスクリプタ・タイプ | 説明 | タイプ | TopLink Workbench | Java |
---|---|---|---|---|
|
リレーショナル・データベース内の表にマップするJavaオブジェクトを記述します。TopLinkでサポートされるすべてのリレーショナル・データベースに対してのみ適用可能です。 |
基本 |
![]() |
![]() |
|
より近密に各オブジェクト・タイプに対応した専用のデータベース・データ・タイプを提供している、リレーショナル・データベースの表にマップされるJavaオブジェクトを記述します。TopLinkでサポートされるリレーショナル・データベースのうち、これら専用のデータ・タイプを提供するリレーショナル・データベースに対してのみ適用可能です。 |
詳細 |
![]() |
![]() |
|
J2Cアダプタを介してEISデータ・ソースにマップするJavaオブジェクトを記述します。 |
基本 |
![]() |
![]() |
|
XMLスキーマ・ドキュメント(XSD)に定義されているXML文書内の複合型へのインメモリー・マッピングを行うJavaオブジェクトを記述します。 |
基本 |
![]() |
![]() |
詳細は、次を参照してください。
この項では、次の内容を含む、TopLinkに固有のディスクリプタの概念について説明します。
ディスクリプタには、あるデータ・ソースによって特定オブジェクト・クラスのインスタンスがどのように表現されるかを定義したすべての情報を格納します。
TopLinkディスクリプタには次の情報を指定します。
ディスクリプタ自体の中で記述する永続Javaクラス、および対応するデータ・ソース(データベース表、XMLの複合型またはEISインタラクション)。
そのクラスの属性とリレーションシップをデータベースにどのように格納するかを記述したマッピングのコレクション。
データ・ソースの主キー情報(またはそれに相当する情報)。
フィールド名の問合せキー(または別名)のリスト。
順序番号の情報。
ディスクリプタの動作を調整するためのオプション・プロパティのセット。リフレッシュ・オプションのキャッシング、アイデンティティ・マップ、オプティミスティック・ロック、イベント・マネージャおよび問合せマネージャに関するサポートが含まれます。
TopLinkがサポートするデータ・ソース・タイプごとに、対応するディスクリプタ・タイプがあります。同一のデータ・ソース・タイプに対して有効なディスクリプタ・タイプが複数ある場合もあります。使用するディスクリプタのタイプにより、定義できるマッピングのタイプが決まります。
表23-2は、プロジェクト、ディスクリプタ、マッピングの関係をまとめたものです。
継承とは、導出されたクラス(子)にそのスーパークラス(親)の特性をどのように受け継がせるかを意味します。ディスクリプタを使用すると、リレーショナル・プロジェクト、EISプロジェクトおよびXMLプロジェクトにおいてクラス間の継承リレーションシップを定義できます。
子クラスのディスクリプタでは、親クラスのディスクリプタに指定されているマッピングをオーバーライドしたり、親クラスのディスクリプタにマップされていない属性をマップできます。
詳細は、「ディスクリプタと継承の概要」を参照してください。
ディスクリプタを使用すると、コンテナ管理の永続性を備えたエンティティBeanまたはBean管理の永続性を備えたエンティティBeanの特性を定義できます。
そのためには、Enterprise Beanのマッピング時に、Beanクラスのディスクリプタを作成します。ただし、ローカル・インタフェース、リモート・インタフェース、ホーム・クラスまたは主キー・クラスのディスクリプタは作成しません。
TopLink Workbenchを使用する場合は、適切なエンティティBeanタイプ(コンテナ管理の永続性またはBean管理の永続性を備えたエンティティBeanなど)を使用してプロジェクトを定義し、Beanのejb-jar.xml
ファイルをTopLink Workbenchプロジェクトにインポートする必要があります。
CMPプロジェクトについては、ejb-jar.xml
ファイルを使用してBeanのマップ対象属性を定義します。コンテナ管理の永続性を備えたBeanのディスクリプタには、CMP固有のオプションを構成するためのCMPポリシーを記述します。
注意: EJB 3.0プロジェクトについては、注釈を使用してBeanのマップ対象属性を定義できます。 |
この項の内容は次のとおりです。
TopLinkのデフォルトでは、すべての変更はコミット時まで保留されます。これは、データ・ソース間のインタラクション数を最小限にとどめるために最も効率的な方法です。
あるいは、エンティティBeanのディスクリプタを構成して非遅延変更が行われるようにすることもできます。すなわち、エンティティBeanの永続フィールドを変更すると、ただちにTopLink CMPによってリレーショナル・スキーマが変更される、ということです。
非遅延変更では、一部のEJBコンテナ(OC4Jなど)のネイティブの動作との下位互換性が得られます。また、トランザクションの一時的な状態を使用してトリガーやストアド・プロシージャなどのためにデータベースとエンティティの変更を同期化するアプリケーションや、同一の主キーを使用して行を削除および作成するアプリケーション、またはトランザクション内の一時的な状態を使用してその他の複雑な問合せを行うアプリケーションなど、高度なアプリケーションにも対応可能となります。
非遅延変更の短所は、データ・ソースとのインタラクションの数が最大になるため、方法としては最も効率が悪いことです。
非遅延変更がサポートされるようにTopLink CMPを構成した場合でも、同じ遅延設定を持つ複数のエンティティBean間でマップされたリレーションシップについての制約は、TopLinkによって引き続き処理されます。ただし、非遅延設定のクラスが遅延設定のクラスに関連付けられており、その2つのクラス間に制約がある場合には、非遅延クラスに加えられた変更に起因するエラーは、開発者が処理する必要があります。
詳細は、「EJB情報によるディスクリプタの構成」を参照してください。
新規のエンティティBeanを作成した場合、デフォルトでは次のようなBeanのライフ・サイクルが想定されます。
ejbCreate
メソッド:
挿入後、EJBコンテナは、作成されたインスタンス用に、データベースによって割り当てられた主キーを取得します。
リレーショナル・プロジェクトの場合:
INSERT INTO ...
SELECT FROM ...
EISプロジェクトの場合:
Write object ...
Find object ...
ejbPostCreate
メソッド:
EJBコンテナにより、コンテナ管理のリレーションシップ(CMR)のフィールドが更新されます。EJBコンテナには、ejbCreate
メソッドで取得された主キーが必要です。
リレーショナル・プロジェクトの場合:
UPDATE SET ...
EISプロジェクトの場合:
Write object ...
なお、データベースに非NULLの外部キー制約がある場合は、ejbCreate
メソッドの実行後にデータ・ソースを変更すると問題が発生することがあります。このような問題を回避するために、一部のアプリケーション・サーバー(OC4Jなど)では、ejbPostCreate
メソッドの実行後に新しいオブジェクトを作成できるようにして、コンテナを使用して外部キー制約を解決するようにしています。
詳細は、「EJB情報によるディスクリプタの構成」を参照してください。
デフォルトでは、特定のオブジェクト・クラスに対してオブジェクト・レベルの読取り問合せを実行すると、そのオブジェクトのディスクリプタにマップされているすべての永続属性がTopLinkによって返されます。この1回の問合せを実行するだけで、対象オブジェクトのすべての永続属性が定義され、さらに、各属性のget
メソッドをコールすることで、属性値をオブジェクトから直接取得できます。
オブジェクトの属性の一部のみが必要な場合は、そのオブジェクトの属性のサブセットのみが返されるようにした方が効率的です。これを行うには、フェッチ・グループを使用してオブジェクトの属性のサブセットを定義し、そのフェッチ・グループをReadObjectQuery
またはReadAllQuery
問合せと関連付けます。
詳細は、次を参照してください。
TopLink Workbenchを使用すると、実行時にディスクリプタがロードされたときにコールされる静的Javaメソッドを関連付けることができます。このメソッドは、ディスクリプタのJavaコードAPIを介して実行時のディスクリプタ・インスタンスを修正できます。このメソッドを使用すると、現在のTopLink Workbenchではサポートされていないような高度な構成オプションを作成できます。ただし、ディスクリプタはセッションが接続される前にのみ修正できます。これは、セッションの接続後にディスクリプタを修正するのは望ましくないためです。
詳細は、「修正メソッドの構成」を参照してください。
2つのオブジェクト、つまり、ソース(親、すなわち所有)オブジェクトとターゲット(子、すなわち被所有)オブジェクトは、両者間に厳密な1対1の関係がある場合、集約によって関連付けられ、ターゲット・オブジェクトのすべての属性は、ソース・オブジェクトと同じデータ・ソース表現から取得できます。つまり、ソース・オブジェクトが存在すればターゲット・オブジェクトも存在する必要があり、ソース・オブジェクトが破棄されればターゲット・オブジェクトも破棄されるということです。
この場合、ソースおよびターゲット・オブジェクトのディスクリプタは、この関係を反映するよう、次の手順で定義する必要があります。
リレーショナル・プロジェクトでは、集約ディスクリプタを定義します(「リレーショナル集約ディスクリプタ」を参照)。
これにより、集約マッピングを構成して(第43章「リレーショナル集約オブジェクト・マッピングの構成」を参照)、ターゲット・オブジェクト内のデータ・メンバーを、ソース・オブジェクトの基礎となるデータベース表のフィールドと関連付けることができます。
リレーショナル・ディスクリプタを集約ディスクリプタとして定義する場合、TopLinkではターゲット・クラスのフィールドごとに1つのマッピング・タイプを指定できますが、フィールドとデータベース表の関連付けは、ソース・ディスクリプタで集約オブジェクト・マッピングを構成した後で可能になります。つまり、ターゲット・クラス・ディスクリプタは各ターゲット・クラス・フィールドがマップされる方法を定義し、ソース・クラス・ディスクリプタは各ターゲット・クラス・フィールドがマップされる場所を定義する、ということです。この仕組みにより、異なる表にマップされた多数の親ディスクリプタ間で同一の集約オブジェクトを共有することができます。
リレーショナル・ディスクリプタを集約ディスクリプタとして定義する場合は、そのクラスが集約オブジェクト・マッピングのターゲットになることをTopLinkに指示します。こうすることで、TopLinkランタイムにより、ターゲット・クラスが次のように処理されます。
ターゲット・クラスの挿入、更新、削除が、ソース・クラスの挿入、更新、削除とパラレルで実行されます。
ターゲット・クラスは単独ではキャッシュされず、ソース・クラスの一部としてキャッシュされます。
作業ユニット内でのターゲット・クラスの読取り、書込み、削除、登録は許可されません。
集約リレーショナル・ディスクリプタを使用する場合は、次の事項に留意する必要があります。
詳細は、「クラスまたは集約タイプとしてのリレーショナル・ディスクリプタの構成」を参照してください。
TopLinkでは、ネストされた集約はサポートされません。図23-1のソース・クラスHockeyPlayer
は、通常の、非集約であるクラス・ディスクリプタです。このクラスは、集約として定義されたターゲット・クラスInfo
を持っています。Info
クラス自体は、ターゲット・クラスPersonalInfo
とTeamInfo
を持っており、この2つはいずれも集約として定義されています。
EJB 3.0では、集約は埋込み可能であることが知られています。EJB 3.0仕様では、埋込み可能である集約に、埋込み可能な別の集約を含めることはできません(つまり、EJB 3.0仕様では、ネストされた集約はサポートされていません)。
ただし、TopLink対応の永続性を備えたEJB 3.0アプリケーションをOC4Jにデプロイすることで、TopLinkによる拡張EJB 3.0仕様を利用して、ネストされた埋込み可能集約を構成できます。ただし、この方法をとった場合、そのアプリケーションは厳密なEJB 3.0仕様準拠ではなくなりますので注意してください。例23-1に、図23-1の各クラスのコード例を示します。ここでは、EJB 3.0の注釈とともにTopLinkによる拡張EJB 3.0仕様を利用し、埋込み可能なInfo
に、同じく埋込み可能なTeamInfo
とPersonalInfo
を埋め込んでいます。
例23-1 ネストされた埋込み可能集約
public class HockeyPlayer implements Serializable {
private int playerId;
private Info Info;
private String lastName;
private String firstName;
...
@Embedded
public Info getInfo() {
return Info;
}
}
@Embeddable
public class Info implements Serializable {
TeamInfo teamInfo; // TopLink extension of EJB 3.0 allows Embeddable with Embeddable
PersonalInfo personalInfo;
public Info() {}
@Embedded
public PersonalInfo getPersonalInfo() {
return personalInfo;
}
public void setPersonalInfo(PersonalInfo personalInfo) {
this.personalInfo = personalInfo;
}
@Embedded
public TeamInfo getTeamInfo() {
return teamInfo;
}
public void setTeamInfo(TeamInfo teamInfo) {
this.teamInfo = teamInfo;
}
}
@Embeddable
public class PersonalInfo implements Serializable {
private int age;
private double weight;
private double height;
...
}
@Embeddable
public class TeamInfo implements Serializable {
private String position;
private int jerseyNumber;
private HockeyTeam hockeyTeam;
...
}
集約として定義されたリレーショナル・ディスクリプタ(「ディスクリプタと継承」を参照)で継承を構成できますが、その場合は継承ツリー内のすべてのディスクリプタが集約である必要があります。集約ディスクリプタとクラス・ディスクリプタは、同じ継承ツリーに置くことはできません。
EJBプロジェクトではリレーショナル集約ディスクリプタを使用できますが、集約として定義されたリレーショナル・ディスクリプタ用にEJB情報を構成することはできません(「ディスクリプタとEJB」を参照)。
リレーショナル集約とEJB 3.0の使用方法の詳細は、「リレーショナル集約とネスト」を参照してください。
EISプロジェクトでは、コンポジット・ディスクリプタを定義できます(「EISコンポジット・ディスクリプタ」を参照)。
作成するEISマッピングのタイプに応じて、EISディスクリプタをコンポジットとして構成するか、ルートとして構成するかが決まります(「コンポジットおよび参照EISマッピング」を参照)。
詳細は、「EISディスクリプタのタイプ(ルートまたはコンポジット)の構成」を参照してください。
コンポジット・ディスクリプタとして定義されたEISディスクリプタ用にEJB情報を構成することはできません(「ディスクリプタとEJB」を参照)。
コンポジットとして定義されたEISディスクリプタ(「ディスクリプタと継承」を参照)で継承を構成できますが、その場合は継承ツリー内のすべてのディスクリプタがコンポジットである必要があります。コンポジットとルートは、同じ継承ツリーに置くことはできません。
XMLプロジェクトでは、ディスクリプタは常にコンポジット・ディスクリプタです。
XMLディスクリプタは常にコンポジットであるため、XMLディスクリプタのタイプを考慮せずにXMLディスクリプタで継承を構成できます(「ディスクリプタと継承」を参照)。
リレーショナル・プロジェクトおよびEISプロジェクトでは、永続データのライフ・サイクルの間にTopLinkがDescriptorEvent
の様々なインスタンスを発生させます(表25-26および表25-28を参照)。各ディスクリプタには、DescriptorEventManager
のインスタンスがあります。このインスタンスは、イベントを受信し、自身に登録されているディスクリプタ・イベント・ハンドラにディスパッチする働きをします。
ディスクリプタ・イベント・ハンドラを使用すると、構築したアプリケーション固有のロジックをディスクリプタ・イベントの発生時に実行でき、永続データのライフ・サイクルの様々な時点において実行可能なカスタマイズ・アクションをとれるようになります。たとえば、ディスクリプタ・イベント・ハンドラを使用して次の動作を実行できます。
永続オブジェクトを他のシステム、サービスおよびフレームワークと同期化すること。TopLinkで認識されない非永続属性を保持すること。
オブジェクトの永続状態が変化したときにアプリケーションの他のオブジェクトに通知すること。
TopLinkのマッピングで直接サポートされていない複雑なマッピングまたは最適化を実装すること。
詳細は、次を参照してください。
各リレーショナル・ディスクリプタとEISディスクリプタには、次の構成に使用できるDescriptorQueryManager
のインスタンスが用意されています。
名前付き問合せ(「ディスクリプタ・レベルでの名前付き問合せの構成」を参照)
基本的な永続性操作に関するカスタムのデフォルト問合せ(「デフォルトの問合せ実装の構成」を参照)
追加の結合式(「追加の結合式の構成」を参照)
問合せマネージャの使用方法の詳細は、「ディスクリプタ問合せマネージャ問合せ」を参照してください。
オブジェクト・アイデンティティを保持する上で重要なのは、各オブジェクト・インスタンスを区別するために一意の値(特定の順序)の割当てを管理することです。詳細は、「プロジェクトおよび順序付け」を参照してください。
順序付けオプションにプロジェクト・レベルとセッション・レベルのいずれを構成するかにより、TopLinkで使用される順序付けのタイプが決まります。CMPプロジェクトの場合、通常はこの順序タイプをプロジェクト・レベルに構成します(「プロジェクト・レベルでの順序付けの構成」を参照)。CMP以外のプロジェクトの場合、セッション・レベルの順序構成を使用して、プロジェクト・レベルの順序構成をセッション単位でオーバーライドすることもできます(「セッション・レベルでの順序付けの構成」を参照)。
各ディスクリプタの参照クラスに対して順序タイプを構成した後は、属性の1つ(通常は主キーとして使用される属性。「主キーの構成」を参照)をディスクリプタ固有の順序と関連付けます(「ディスクリプタ・レベルでの順序付けの構成」を参照)。
次に示すロック・ポリシーのいずれかを使用してディスクリプタを構成し、ドメイン・オブジェクトへの同時アクセスを制御できます。
オプティミスティック: すべてのユーザーにデータへの読取りアクセス権限があります。ユーザーが変更を加えようとすると、アプリケーションにより、ユーザーがデータを読み取ってから、そのデータが変更されていないかが確認されます(「オプティミスティック・バージョン・ロック・ポリシー」および「オプティミスティック・フィールド・ロック・ポリシー」を参照)。
ペシミスティック: データを更新する目的でそのデータにアクセスする最初のユーザーが、更新を完了するまでデータをロックします(「ペシミスティック・ロック・ポリシー」を参照)。
ロックなし: 複数のユーザーが互いの変更内容を上書きする操作は阻止されません。
ほとんどのタイプのアプリケーションでは、ユーザー同士が互いの変更内容を上書きできないようにするために、オプティミスティック・ロックを使用することをお薦めします。
詳細は、次を参照してください。
ディスクリプタに記述したクラスに関連付けられているデータ・ソースのデータ・タイプがTopLinkランタイムに認識されるようにするには、デフォルトのルート要素を使用して、EISルート・ディスクリプタ(「デフォルトのルート要素の構成」を参照)およびXMLディスクリプタ(「デフォルトのルート要素の構成」を参照)を構成します。
注意: 参照オブジェクトの未定義のドキュメント・ルート要素は、コレクション・マッピングおよびオブジェクト・マッピングによるマーシャリング中に無視されます。 |
この項では、デフォルトのルート要素の概要と、それがTopLinkでどのように使用されるかについて説明します。
例23-2に示すCustomer
クラスとAddress
クラス、およびそれらのマッピングについて考えてみます。
例23-2 CustomerクラスとAddressクラス
Class:
CustomerDefault Root:
customerAttributes and Mappings:
name:String Drect Mapping to name/text() billingAddress:Address Composite Object Mapping to billing-address shippingAddress:Address Composite Object Mapping to shipping-addressClass:
AddressDefault Root:
addressAttributes and Mappings:
street:String Direct Mapping to street/text() city:String Direct Mapping to city/text()
これらのクラスは、例23-3に示すXMLスキーマに対応しています。
例23-3 CustomerおよびAddressスキーマ
<xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsd:complexType name="address-type"> <xsd:sequence> <element name="street" type="xsd:string"/> <element name="city" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="customer" type="customer-type"/> <xsd:complexType name="customer-type"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="billing-address" type="address-type"/> <xsd:element name="shipping-address" type="address-type"/> </xsd:sequence> </xsd:complexType> </xsd:schema>
Customer
クラスのインスタンスをXMLに永続化する際には、TopLinkランタイムで次の処理が行われます。
デフォルトのルート要素が取得されます。
Customer
クラス・インスタンスは、XML文書のルートに対応しています。TopLinkランタイムは、ディスクリプタ(customer
)に指定されているデフォルトのルート要素を使用して、XML文書を開きます。次に、ディスクリプタに含まれるマッピングを使用して、そのオブジェクトの属性をマーシャリングします。
<customer> <name>…</name> </customer>
TopLinkランタイムは、たとえば、オブジェクト属性billingAddress
に遭遇すると、この属性に関連付けられているマッピングをチェックし、処理をどの要素(billing-address
)に移すかを判別します。
<customer> <name>…</name> <billing-address/> </customer>
TopLinkランタイムはマッピングの参照ディスクリプタ(Address
)をチェックして、永続化する属性を判別します。
<customer> <name>…</name> <billing-address> <street>…</street> <city>…</city> </billing-address> </customer>
リレーショナル・ディスクリプタには、リレーショナル・データベース内の表にマップするJavaオブジェクトを記述します。リレーショナル・ディスクリプタはリレーショナル・プロジェクトで使用します(「リレーショナル・プロジェクト」を参照)。
リレーショナル・ディスクリプタをリレーショナル・プロジェクトで使用すると、リレーショナル・マッピングを構成できます(「リレーショナル・マッピングのタイプ」を参照)。
詳細は、次を参照してください。
オブジェクト・リレーショナル・パラダイムは、従来のリレーショナル・データベースを拡張してオブジェクト指向の機能を組み込むためのものです。Oracle、IBM DB2、Informixおよびその他のDBMSデータベースでは、ユーザーは、複雑なデータの格納、アクセス、使用をより高度な方法で行うことができます。オブジェクト・リレーショナル標準は、主にデータベースのデータ構造とSQL(SQL 3)の拡張を目的として改良が重ねられている標準です。
オブジェクト・リレーショナル・ディスクリプタには、より近密に各オブジェクト・タイプに対応している専用のリレーショナル・データベース・タイプにマップされるJavaオブジェクトを記述します。これら専用のオブジェクト・リレーショナル・データベース・タイプを使用すると、リレーショナル・データベース表へのオブジェクトのマッピングが容易になります。ただし、これら専用のオブジェクト・リレーショナル・データベース・タイプは一部のリレーショナル・データベースではサポートされていません。
リレーショナル・プロジェクトでオブジェクト・リレーショナル・ディスクリプタを使用すると、それらの専用オブジェクト・リレーショナル・データベース・データ・タイプへのオブジェクト・リレーショナル・マッピングを構成することができます(「オブジェクト・リレーショナル・マッピング・タイプ」を参照)。
詳細は、次を参照してください。
EISディスクリプタには、J2Cアダプタを介してEISデータ・ソースにマップするJavaオブジェクトを記述します。
TopLink Workbenchで作成したEISプロジェクトでEISディスクリプタを使用すると、XMLレコードへのEISのマッピング(「EISマッピングのタイプ」を参照)を構成できます。
Javaで作成したEISプロジェクトでEISディスクリプタを使用すると、サポートされている任意のEISレコード・タイプ(XML、マップ済、索引付き)へのEISのマッピングを構成できます。
詳細は、次を参照してください。
XMLディスクリプタには、XMLスキーマ・ドキュメント(XSD)に定義されている単純および複合型に対してマップするJavaオブジェクトを記述します。
XMLディスクリプタをXMLプロジェクトで使用すると、XSDに定義されているXML要素へのXMLのマッピング(「XMLマッピングのタイプ」を参照)をメモリー内に構成できます。
詳細は、次を参照してください。
継承とは、導出されたクラスにそのスーパークラスの特性をどのように受け継がせるかを意味します。ディスクリプタを使用すると、リレーショナル・プロジェクト、EISプロジェクトおよびXMLプロジェクトにおいてクラス間の継承リレーションシップを定義できます。
図23-2に、Java継承階層の代表例としてVehicle
というオブジェクト・モデルを示します。ルート・クラスのVehicle
には、2つブランチ・クラスFueledVehicle
およびNonFueledVehicle
が含まれています。各ブランチ・クラスには、それぞれCar
およびBicycle
というリーフ・クラスが含まれます。
TopLinkが継承階層で認識するクラスは、次の3つの種類です。
ルート・クラスには、サブクラス階層内のインスタンス化可能なすべてのクラスに関する情報が格納されます。デフォルトでは、ルート・クラスに対して実行された問合せにより、ルート・クラスおよびインスタンス化可能なサブクラスのインスタンスが返されます。ただし、ルート・クラスの構成方法によっては、ルート・クラスに対する問合せ時にサブクラスのインスタンスを省いて、ルート・クラス自体のインスタンスのみを返すこともできます。
たとえば、図23-2のVehicle
クラスが、ルート・クラスです。
ブランチ・クラスは、永続スーパークラスの他にサブクラスを持つものです。デフォルトでは、ブランチ・クラスに対して実行された問合せにより、ブランチ・クラスおよびそのサブクラスのインスタンスが返されます。ただし、ルート・クラスの場合と同様に、ブランチ・クラスの構成方法によっては、ブランチ・クラスに対する問合せ時にサブクラスのインスタンスを省いて、ブランチ・クラス自体のインスタンスのみを返すこともできます。
たとえば、図23-2のFueledVehicle
クラスが、ブランチ・クラスです。
リーフ・クラスには、階層内の永続スーパークラスがありますが、サブクラスはありません。リーフ・クラスに対して実行された問合せにより、リーフ・クラスのインスタンスのみが返されます。
たとえば、図23-2のCar
クラスが、リーフ・クラスです。
子クラスのディスクリプタでは、親クラスのディスクリプタに指定されているマッピングをオーバーライドしたり、親クラスのディスクリプタにマップされていない属性をマップできます。
この項では、次の内容について説明します。
親(ルート)クラス・ディスクリプタに対する継承の構成方法の詳細は、「親(ルート)ディスクリプタに対する継承の構成」を参照してください。
子(ブランチまたはリーフ)クラス・ディスクリプタに対する継承の構成方法の詳細は、「子(ブランチまたはリーフ)クラス・ディスクリプタに対する継承の構成」を参照してください。
継承を構成する場合は、ルート・クラス・ディスクリプタに、インスタンス化先のサブクラスの選択の方法を構成します。
これは、次のいずれかの方法で行えます。
注意: 継承階層内のすべてのリーフ・クラスにはクラス・インジケータが必須で、かつこれらのリーフ・クラスは同じタイプのクラス・インジケータ(フィールドまたはクラス抽出メソッド)を持つ必要があります。 |
クラスの永続属性を使用すると、インスタンス化先のサブクラスを指定できます。たとえば、リレーショナル・ディスクリプタでは、ルート・クラス表のクラス・インジケータ・フィールドを使用できます。ただし、クラス・インジケータ・フィールドには、読取り専用に設定されていないダイレクト・マッピングを関連付けないでください。
注意: クラス・インジケータ・フィールドが主キーの一部である場合は、このフィールドに対して書込み専用トランスフォーメーション・マッピングを定義します(第45章「リレーショナル・トランスフォーメーション・マッピングの構成」を参照)。 |
クラス・インジケータ・フィールドでは、値として文字列または数値を使用できます。
ルート・クラス・ディスクリプタによって、クラス・インジケータ・フィールドの値をインスタンス化されるクラスに変換する方法を指定する必要があります。
そのための方法の1つは、クラス・インジケータ・ディクショナリ(クラス・インジケータ・フィールドに格納される単純なキーを、インスタンス化するクラスに関連付けるキー値のコレクション)を使用して、ルート・クラス・ディスクリプタを構成することです。表23-3に、図23-2で示したVehicle
クラスのサブクラスのクラス・インジケータ・ディクショナリを示します。
もう1つの方法は、単純にクラス名自体をクラス・インジケータ・フィールドへの値として格納することです。こうすると、クラス名の長さの範囲内で通常より長めのキー値を使用してまでクラスごとに一意のインジケータを定義することの必要性から解放されます。
オブジェクトのデータ・ソース・レコード内で利用可能なすべての情報に基づいて、クラス・インジケータを計算するJavaメソッドを定義することができます。このようなメソッドをクラス抽出メソッドといいます。
クラス抽出メソッドを使用すると、データ・モデルに明示的なクラス・インジケータ・フィールドを含める必要がなくなり、また、複雑すぎてクラス・インジケータ・フィールドには定義できないリレーションシップを処理できます。
クラス抽出メソッドには次の特性が必要です。
ルート・ディスクリプタのクラスをベースにして定義されていること
静的であること
引数としてRecord
をとること
入出力引数であるRecord
にjava.lang.Class
オブジェクトを出力すること
また、必要に応じて、OnlyInstancesExpressionとWithAllSubclassesExpressionも定義します(「OnlyInstancesExpressionとWithAllSubclassesExpressionの指定」を参照)。
表23-4は、一例としてEMPLOYEE
という表の行を示したものです。ベース・クラスはEmployee
クラスです。Director
、Manager
、Programmer
およびTechWriter
クラスはいずれもEmployee
クラスから導出されます。ただし、構築するアプリケーションでは、Manager
、Programmer
およびTechWriter
クラスのインスタンスはEmployee
のインスタンスとして表現するものの、Director
のインスタンスはDirector
のインスタンスとして表現する必要があります。クラスとJOB_TYPE
フィールド値は1対1で対応していないため、JOB_TYPE
フィールド単独ではクラス・インジケータ・フィールドとして機能しません(「クラス・インジケータ・フィールドの使用」を参照)。この問題を解決するには、例23-4に示すクラス抽出メソッドを使用できます。
表23-4 EMPLOYEE表
ID | NAME | JOB_TYPE | JOB_TITLE |
---|---|---|---|
732 |
Bob Jones |
1 |
Manager |
733 |
Sarah Smith |
3 |
Technical Writer |
734 |
Ben Ng |
2 |
Director |
735 |
Sally Johnson |
3 |
Programmer |
例23-4 クラス抽出メソッド
... // If the JOB_TYPE field value in record equals 2, return the Director class. // Return the Employee class for all other JOB_TYPE field values public static Class getClassFromRecord(Record record) { if (record.get("JOB_TYPE").equals(new Integer(2)) { return Director.class; } else { return Employee.class; } }
クラス抽出メソッドを使用して継承を構成した場合、Oracle TopLinkではルート・クラスに関する問合せのためのSQLは生成されません。
クラス抽出メソッド(「クラス抽出メソッドの使用」を参照)を使用する場合は、共通の表を使用するすべてのクラスの兄弟インスタンスを正しくフィルタ処理するための式を、TopLinkに指定する必要があります(「親(ルート)クラス・ディスクリプタに関する継承式の構成」を参照)。
リレーショナルおよびEISプロジェクトの場合、TopLinkでは、継承階層内のすべてのクラスが、ルート・ディスクリプタに設定されているのと同じ主キーを持っていることが前提とされます。複数の主キーを持つデータ・ソース表現に関連付けられた子ディスクリプタには、ルートの主キーとローカルの主キーとの間のマッピングを定義する必要があります。
リレーショナル・プロジェクトでは、継承階層を単一表(「単一表の継承」を参照)にも複数表(「複数表の継承」を参照)にもマッピングできます。この選択肢を使用することで、アプリケーションに適した形で、格納効率とアクセス効率の間でバランスをとることができます。
この例では、複数レベルの継承を持つクラスを単一表に格納して、データベースのアクセス速度を最適化します。
図23-3に示すとおり、図23-2の継承階層全体で同一の表を共有できます。FueledVehicle
の属性がNonFueledVehicle
にない場合でも、FueledVehicle
およびNonFueledVehicle
サブクラスは同じ表を共有できます。NonFueledVehicle
のインスタンスはデータベース・リソースを消費します。これは、データベースがNonFueledVehicleの使用されない部分の行に対しても領域を割り当ててしまうためです。とはいえ、この方法を使用すると、その他のFueledVehicle
情報を取得する際に別の表に結合する必要がなくなるため、アクセス時間が短縮されます。
図23-3に示したとおり、この方法ではクラス・インジケータ・フィールドを使用します。詳細は、「クラス・インジケータの指定」を参照してください。
この例では、複数レベルの継承を持つクラスを複数表に格納して、データベースのアクセス速度を最適化します。
図23-2に示した継承階層において、追加の属性を必要とするサブクラスについては、スーパークラスの単一表でなく複数表を使用します。これにより、データベース内で、実際には使用されないフィールドが存在することがなくなり、記憶域が最適化されます。ただし、TopLinkがオブジェクトをインスタンス化する場合には、複数表から読取りを行う必要があるため、パフォーマンスが低下します。TopLinkはまずクラス・インジケータ・フィールド(「クラス・インジケータの指定」を参照)を調べて、作成するオブジェクトのクラスを判別してから、そのクラスのディスクリプタを使用してサブクラスの表から属性を読み取ります。
図23-4は、TopLinkでのFUELEDVHCL
、CAR
およびBICYCLE
表の実装を示したものです。すべてのオブジェクトはVEHICLE
表に格納されています。また、FueledVehicle
、Car
、Bicycle
の情報はセカンダリ表に格納されています。なお、NonFueledVehicle
クラスには、属性もリレーションシップもないため、セカンダリ表は不要です。
注意: 一般的に、複数表の継承の使用は、結合の頻度と複数表からのフェッチの頻度が高くなるため、非効率です。 |
ルートまたはブランチの継承ディスクリプタに、複数表にわたるサブクラスがある場合は、データベース・ビューを構成してすべてのサブクラス表を外部結合することにより、親ディスクリプタに対する問合せのパフォーマンスを最適化することができます。これにより、TopLinkはすべてのサブクラス・インスタンスを複数回ではなく1回の問合せでフェッチできるようになります。また、親クラスに対してカーソルまたは順序付けを使用した問合せも実行できます。
データベースのビューは、すべてのサブクラス表を外部結合した1つのデータベース・ビューとして定義する必要があります。詳細は、「問合せでのサブクラス読取り機能の構成」を参照してください。
リレーショナル・ディスクリプタは集約ディスクリプタとして、EISディスクリプタはコンポジット・ディスクリプタとして指定できます。XMLディスクリプタは必ずコンポジット・ディスクリプタである必要があります(「ディスクリプタと集約」を参照)。
リレーショナル集約ディスクリプタで継承を構成する場合は、継承ツリー内のすべてのディスクリプタが集約である必要があります。つまり、集約クラスと非集約クラスのディスクリプタを同じ継承ツリーに置くことはできません。
同様に、EISコンポジット・ディスクリプタで継承を構成する場合も、継承ツリー内のすべてのディスクリプタはコンポジットである必要があります。つまり、コンポジット・クラスと非コンポジット・クラスのディスクリプタを同じ継承ツリーに置くことはできません。
XMLディスクリプタで継承を構成する場合は、すべてのXMLディスクリプタがコンポジットであるため、継承はディスクリプタ・タイプによる制限を受けません。
この項では、TopLinkでサポートされている次のような様々なタイプのロック・ポリシーについて説明します。
詳細は、「ロック・ポリシーの構成」を参照してください。
オプティミスティック・ロックを使用した場合、すべてのユーザーにデータへの読取りアクセス権限があります。ユーザーが変更を加えようとすると、アプリケーションにより、ユーザーがデータを読み取ってから、そのデータが変更されていないかが確認されます。
オプティミスティック・バージョン・ロック・ポリシーでは、バージョン・フィールド(書込みロック・フィールド)を使用して、オプティミスティック・ロックが実行されます。バージョン・フィールドは、参照クラス内に作成し、オブジェクト変更がコミットされるたびにTopLinkによって更新されます。
TopLinkは、データ・ソースからオブジェクトを読み取るときにこのバージョン・フィールドの値をキャッシュします。クライアントがオブジェクトに書き込もうとすると、TopLinkはキャッシュしたバージョン値とデータ・ソース内の最新のバージョン値を次のように比較します。
2つの値が一致した場合は、オブジェクト内のバージョン・フィールドを更新し、データ・ソースに対する変更内容をコミットします。
2つの値が一致しなかった場合は、そのクライアントが最初にオブジェクトを読み取った後に別のクライアントがそのオブジェクトを更新したことを意味するため、書込み操作を却下します。
TopLinkには、次のようなバージョン・ベースのオプティミスティック・ロック・ポリシーが用意されています。
VersionLockingPolicy
: numericタイプのバージョン・フィールドが必要です。TopLinkは、値を1ずつ増分することによってこのバージョン・フィールドを更新します。
TimestampLockingPolicy
: timestampタイプのバージョン・フィールドが必要です。TopLinkは、新しいタイムスタンプを挿入することによってこのバージョン・フィールドを更新します(このポリシーは、タイムスタンプをデータ・ソースまたはローカル時間から取得するように構成できます。デフォルトではデータ・ソースから取得されます)。
注意: 次の理由から、通常はnumericタイプのバージョンのロックをお薦めします。
|
オプティミスティック・ロック違反により更新が失敗すると、TopLinkではOptimisticLockException
がスローされます。この例外は、データベースの変更を行っているアプリケーションで処理する必要があります。アプリケーションは、ロックの競合をクライアントに通知し、オブジェクトをリフレッシュして、クライアントに変更内容の再適用を依頼する必要があります。
バージョン値は、オブジェクト内にマップ済属性として格納するか、キャッシュに格納するかを選択できます。3層アプリケーションでは、オブジェクトの更新時にバージョン値が確実にクライアントに渡されるようにするため、オブジェクト内にバージョン値を格納しておく方法が一般的です(「3層アプリケーションでのロック」を参照)。
バージョン値をキャッシュに格納する場合、バージョン値のマッピングは必要ありません。バージョン・フィールドをマッピングする場合は、マッピングを読取り専用として構成する必要があります(「読取り専用マッピングの構成」を参照)。
私有の子オブジェクトの変更時にその親オブジェクトのバージョン・フィールドが確実に更新されるようにするには、「オプティミスティック・バージョン・ロック・ポリシーとカスケード」を使用することを検討します。
作業ユニットによるオプティミスティック・バージョン・ロックを使用する場合は、「forceUpdateToVersionFieldによるオプティミスティック読取りロックの使用」を検討します。
使用するデータベース・スキーマが、親オブジェクトおよびその私有の子オブジェクトの両方を同じ表内に格納する設計になっている場合には、その子オブジェクトを更新すると、親オブジェクトのバージョン・フィールドが更新されます。
一方、親オブジェクトおよびその私有の子オブジェクトを異なる表に格納する場合は、デフォルトでは、子を変更しても、親のバージョン・フィールドは更新されません。
この場合に親オブジェクトのバージョン・フィールドを確実に更新するには、親オブジェクトのバージョン・フィールドを手動で更新します(「forceUpdateToVersionFieldによるオプティミスティック読取りロックの使用」を参照)。または、TimestampLockingPolicy
ポリシーを使用しているのであれば、子オブジェクトのバージョン・フィールドの更新が親に自動的にカスケードされるようにTopLinkを構成する方法もあります(「オプティミスティック・ロック・ポリシーのカスケードの構成」を参照)。
オプティミスティック・バージョン・ロックのカスケード機能を有効化した場合に、私有の子オブジェクトを変更すると、TopLinkはその私有されている外部参照マッピングを走査し、ルートに向かってすべての親オブジェクトを更新します。
オプティミスティック・バージョン・ロックのカスケードは、子オブジェクトが作業ユニット内に登録されている場合にのみ適用されます。
TopLinkでは、次の場合にオプティミスティック・バージョン・ロックのカスケードがサポートされます。
私有の1対1および1対多マッピングでのオブジェクト変更
次のコレクション・マッピング(私有かどうかは問わない)でのリレーションシップ変更(追加または削除)
ダイレクト・コレクション
1対多
多対多
集約コレクション
図23-5に例示したオブジェクトの図について考えてみます。
この例では、ObjectA
がObjectB
を私有し、ObjectB
はObjectC
を私有し、ObjectC
はObjectD
を私有します。
ObjectB
を作業ユニットに登録し、ObjectB
を変更して、作業ユニットをコミットしたとします。この場合、ObjectB
はObjectA
のキャッシュをチェックし、値が存在しない場合にはデータベースに対してObjectA
を問い合せます。次に、ObjectB
は自身の変更をObjectA
に通知します。ObjectA
は、自身に対応する表に変更がない場合でも、自身のバージョン・オプティミスティック・ロック・フィールドを更新します。
ObjectA
を作業ユニットに登録して、ObjectA
→ObjectB
→ObjectC
→ObjectD
の順にアクセスし、ObjectD
のフィールドを変更して、作業ユニットをコミットしたとします。この場合は、ObjectD
が自身の変更をObjectC
に通知します。ObjectC
は、自身に対応する表に変更がない場合でも、自身のバージョン・オプティミスティック・ロック・フィールドを更新します。次に、ObjectC
はObjectD
の変更をObjectB
に通知します。次に、ObjectB
がObjectD
の変更をObjectA
に通知します。ObjectA
は、自身に対応する表に変更がない場合でも、自身のバージョン・オプティミスティック・ロック・フィールドを更新します。
オプティミスティック・ロックで、オプティミスティック・ロックのバージョンをキャッシュに格納する場合、ロックされたオブジェクトの値をロールバックするにはUnitOfWork
メソッドcommitAndResumeOnFailure
(「コミット後の作業ユニットの再開」を参照)を使用します。
ロックされた複数のバージョンを1つのオブジェクトに格納する場合は、更新失敗時に各オブジェクト(すなわち、オブジェクトのバージョン)をリフレッシュする必要があります。あるいは、失敗時に新しい作業ユニットを取得して、そのユニットに変更を再適用することもできます。
オプティミスティック・フィールド・ロック・ポリシーでは、表内に現存する1つ以上のフィールドを使用して、クライアントが対象オブジェクトを読み取った以後にそのオブジェクトが変更されたかどうかを判別することによって、オプティミスティック・ロックが実行されます。
ユーザーがオブジェクトを最初に読み取ったとき、またはオブジェクトを作業ユニットに登録したときに、作業ユニットにより、そのオブジェクトの元の状態がキャッシュされます。コミット時には、ロック・フィールドの元の値と更新中のデータ・ソースの現在の値が、作業ユニットにより比較されます。ロック・フィールドのいずれかの値が変更されていた場合には、オプティミスティック・ロック例外がスローされます。
TopLinkには、次のようなオプティミスティック・フィールド・ロック・ポリシーが用意されています。
AllFieldsLockingPolicy
: 更新または削除操作を行うと、TopLinkは対象オブジェクトのすべてのフィールドをデータ・ソース内のすべてのフィールドと比較します。いずれかのフィールドの元の値がデータ・ソース内の値と異なる場合、その書込み操作は却下されます。
たとえば、ある顧客の姓を変更した場合、TopLinkにより次のようなSQLが生成されます。
UPDATE CUSTOMER SET LNAME='new last name' WHERE ID=7 AND LNAME='old last name' AND FNAME='Donald' AND B_DAY='1972' AND CREDIT_RATING='A+' AND EYE_COLOR='Blue'
このフィールド・ロック・ポリシーの主な短所は、特に、多くの属性を持つオブジェクトの変更時に、最適なパフォーマンスが得られない点です。
注意: この比較は、表単位でのみ行われます。複数表にマップされているオブジェクト(複数表の継承)に対して更新操作を行うと、変更された各表の変更されたフィールドのみがwhere 句に表示されます。 |
ChangedFieldsLockingPolicy
: 更新操作を行うと、TopLinkは対象オブジェクトの変更されたフィールドのみをデータ・ソース内の対応フィールドと比較します。いずれかのフィールドの元の値がデータ・ソース内の値と異なる場合、その書込み操作は却下されます。削除に対しては、TopLinkではフィールド比較は実行されません。
このフィールド・ロック・ポリシーの主な長所は、複数のフィールドを同時に更新できる点です。たとえば、ChangedFieldsLockingPolicy
を使用してCustomer
ディスクリプタを構成した場合に、あるスレッドで顧客の姓が更新され、別のスレッドではその顧客の信用格付けが更新されると、TopLinkにより次のようなSQLが生成されます。
// Unit of Work 1 UPDATE CUSTOMER SET LNAME='new name' WHERE ID=7 AND LNAME='old name' // Unit of Work 2 UPDATE CUSTOMER SET CREDIT_RATING='B' WHERE ID=7 AND CREDIT_RATING='A+'
SelectedFieldsLockingPolicy
: 更新または削除操作を行うと、TopLinkは対象オブジェクトの選択されたフィールドのみを、データ・ソース内の対応フィールドと比較します。いずれかのフィールドのキャッシュされた値がデータ・ソース内の値と異なる場合、その書込み操作は却下されます。
たとえば、Customer
属性のLNAME
とCREDIT_RATING
を選択した場合、TopLinkは実行時に次のようなSQLを生成します。
UPDATE CUSTOMER SET LNAME='new name' WHERE ID=7 AND LNAME='old name' AND CREDIT_RATING='A+'
オプティミスティック・ロック違反により更新が失敗すると、TopLinkではOptimisticLockException
がスローされます。この例外は、データベースの変更を行っているアプリケーションで処理する必要があります。アプリケーションは、ロックの競合をクライアントに通知し、オブジェクトをリフレッシュして、クライアントに変更内容の再適用を依頼する必要があります。
フィールド・ロック・ポリシーを使用する場合は、データ・ソースを更新するために作業ユニットを使用する必要があります。
ペシミスティック・ロックを使用した場合は、データを更新する目的でそのデータにアクセスする最初のユーザーが、更新を完了するまでデータをロックします。
ペシミスティック・ロック・ポリシーを使用する場合は、更新をただちに失敗させるか、読取りロックが取得されるまで待機させるようにポリシーを構成できます。
ペシミスティック・ロック・ポリシーを使用できるのは、コンテナ管理の永続性タイプ(「永続性タイプの構成」を参照)を指定し、EJB情報を持つディスクリプタ(「EJB情報によるディスクリプタの構成」を参照)を使用したプロジェクトのみです。
また、問合せレベルでペシミスティック・ロック機能(ペシミスティック・ロック・ポリシーではない)を使用することもできます(「名前付き問合せのオプションの構成」を参照)。
コンテナ管理の永続性を備えたエンティティBeanでペシミスティック・ロックが使用される場合、TopLinkではこのロックが最適化されます。問合せをペシミスティック・ロックに設定し、その問合せを独自の新規トランザクション(ファインダの実行後に終了するトランザクション)内で実行すると、TopLinkによりロック設定が上書きされ、SQLにFOR UPDATE
は追加されません。ただし、ペシミスティック・ロック問合せがFOR UPDATEを含むSQL文字列でユーザーによりカスタマイズされている場合、この最適化の使用により不適切な結果が生じることがあります。この場合、最適化の条件が存在すると、問合せはペシミスティック・ロックを使用しないようリセットされますが、SQLはそのままの状態で残るため、問合せのロック設定が問合せのSQL文字列と競合することになります。この問題を回避するには、次のいずれかの方法を使用します。
選択基準としてEJB QLまたはTopLinkの式(第95章「TopLinkの式の概要」を参照)を使用します。これにより、TopLinkでSQLの生成を制御します。
最適化の条件をなくすため、ファインダをトランザクション内に配置します。
3層アプリケーションを構築する場合は、オブジェクトが正しくロックされるようにするため、そのオブジェクトが編集用にクライアントに送信される前にロックを取得できるようにする必要があります。
オプティミスティック・ロックを使用する場合、オブジェクトを正しくロックするには次の2つの選択肢があります。
オブジェクト内のオプティミスティック・ロック・フィールドを読取り専用以外にマップし、読取り時にバージョンをクライアントに渡し、更新時にサーバーに戻します。
バージョン・フィールドに対して読取り専用以外のマッピングを定義し、バージョン値がキャッシュではなくオブジェクト内に格納されるようにオプティミスティック・ロック・ポリシーを設定する必要があります。これは、TopLink Workbenchで「ロック」タブの「キャッシュにバージョンを保存」の選択を解除することで設定できます(「TopLink Workbenchの使用」を参照)。
クライアントがオブジェクトを更新目的で読み取るときに、元のバージョン値がクライアントに確実に送信されるようにします。次に、クライアントが、元のバージョン値を更新情報とともに戻す必要があります。また、このバージョンは、サーバー上の新しい作業ユニット内に登録されたかまたは読み込まれた後に、更新対象のオブジェクト内に設定される必要があります。
クライアントとの対話が完了するまで作業ユニットを保持します。
ステートフル・セッションBeanを介して、またはHTTPセッションにおいて、更新対象オブジェクトの読取りに使用する作業ユニットを、クライアントとの対話が完了するまで保管します。
オブジェクトをクライアントに更新用に渡す前に、この作業ユニットからオブジェクトを読み取っておく必要があります。これにより、作業ユニットのキャッシュまたは作業ユニットのクローンに元のバージョン値を保管しておけます。
この同じ作業ユニットを更新でも必ず使用します。
1番目の選択肢の方が一般的に使用され、ステートレス・アプリケーションを開発する場合には必須となります。
ペシミスティック・ロックを使用する場合は、作業ユニットを使用して、オブジェクトが読み取られる前にデータベース・トランザクションを開始する必要があります。この作業ユニットとデータベース・トランザクションは、クライアントがオブジェクトを編集して更新するまでの間、保持する必要があります。この同じ作業ユニットをオブジェクトの更新でも必ず使用します。(通常クライアントとの対話中はデータベース・トランザクションをオープンにしておくことは望ましくないとされている)3層Webアプリケーションを構築する場合は、一般的にはペシミスティック・ロックよりもオプティミスティック・ロックの方が適しています(「3層アプリケーションでのオプティミスティック・ロック」を参照)。
ディスクリプタAPIを使用すると、Javaコードを介してTopLinkディスクリプタを定義または修正することができます。ディスクリプタAPIのクラスは、主としてoracle.toplink.descriptors
パッケージに含まれています。このようなクラスには次のものがあります。
ClassDescriptor
(抽象汎用ディスクリプタAPI)
RelationalDescriptor
(リレーショナル・プロジェクト固有API)
DescriptorEventManager
(イベントAPI)
DescriptorQueryManager
(問合せAPI)
InheritancePolicy
InterfacePolicy
ReturningPolicy
ロック・ポリシー(各種のオプティミスティック・ロック・ポリシー)
オブジェクト・リレーショナル、EISおよびXMLプロジェクト用のディスクリプタ・クラスは、それぞれoracle.toplink.objectrelational
、oracle.toplink.eis
およびoracle.toplink.ox
パッケージに含まれています。
この項では、Oracle TopLink Foundation Libraryの重要なディスクリプタ・クラスについて説明します。次の項にそのようなクラスが記載されています。
例23-5は、クラスoracle.toplink.descriptors.ClassDescriptor
から導出されたディスクリプタ・タイプを示したものです。