この章では、リレーショナル・ディスクリプタの概要と、リレーショナル・プロジェクトにおける継承の役割や様々なタイプのディスクリプタについて説明します。
この章の内容は次のとおりです。
複数のタイプのTopLinkディスクリプタに共通のディスクリプタの概念と機能の詳細は、第16章「ディスクリプタの概要」を参照してください。
リレーショナル・ディスクリプタには、リレーショナル・データベース内の表にマップするJavaオブジェクトを記述します。リレーショナル・ディスクリプタはリレーショナル・プロジェクトで使用します(第18章「リレーショナル・プロジェクトの概要」を参照)。
リレーショナル・ディスクリプタをリレーショナル・プロジェクトで使用すると、リレーショナル・マッピングを構成できます(27.1項「リレーショナル・マッピングのタイプ」を参照)。
詳細は、次を参照してください。
リレーショナル・プロジェクトでは、集約ディスクリプタを定義します(22.2.1.2項「リレーショナル集約ディスクリプタの作成」を参照)。
これにより、集約マッピングを構成して(第37章「リレーショナル集約オブジェクト・マッピングの構成」を参照)、ターゲット・オブジェクト内のデータ・メンバーを、ソース・オブジェクトの基礎となるデータベース表のフィールドと関連付けることができます。
リレーショナル・ディスクリプタを集約ディスクリプタとして定義する場合、TopLinkではターゲット・クラスのフィールドごとに1つのマッピング・タイプを指定できますが、フィールドとデータベース表の関連付けは、ソース・ディスクリプタで集約オブジェクト・マッピングを構成した後で可能になります。つまり、ターゲット・クラス・ディスクリプタは各ターゲット・クラス・フィールドがマップされる方法を定義し、ソース・クラス・ディスクリプタは各ターゲット・クラス・フィールドがマップされる場所を定義する、ということです。この仕組みにより、異なる表にマップされた多数の親ディスクリプタ間で同一の集約オブジェクトを共有することができます。
リレーショナル・ディスクリプタを集約ディスクリプタとして定義する場合は、そのクラスが集約オブジェクト・マッピングのターゲットになることをTopLinkに指示します。こうすることで、TopLinkランタイムにより、ターゲット・クラスが次のように処理されます。
ターゲット・クラスの挿入、更新、削除が、ソース・クラスの挿入、更新、削除とパラレルで実行されます。
ターゲット・クラスは単独ではキャッシュされず、ソース・クラスの一部としてキャッシュされます。
作業ユニット内でのターゲット・クラスの読取り、書込み、削除、登録は許可されません。
集約リレーショナル・ディスクリプタを使用する場合は、次の事項に留意する必要があります。
詳細は、23.6項「クラスまたは集約タイプとしてのリレーショナル・ディスクリプタの構成」を参照してください。
TopLinkでは、ネストされた集約はサポートされません。図21-1のソース・クラスHockeyPlayer
は、通常の、非集約であるクラス・ディスクリプタです。このクラスは、集約として定義されたターゲット・クラスInfo
を持っています。Info
クラス自体は、ターゲット・クラスPersonalInfo
とTeamInfo
を持っており、この2つはいずれも集約として定義されています。
EJB 3.0では、集約は埋込み可能であることが知られています。EJB 3.0仕様では、埋込み可能である集約に、埋込み可能な別の集約を含めることはできません(つまり、EJB 3.0仕様では、ネストされた集約はサポートされていません)。
ただし、TopLink対応の永続性を備えたEJB 3.0アプリケーションをOracle WebLogic Serverにデプロイすることで、EclipseLinkによる拡張EJB 3.0仕様を利用して、ネストされた埋込み可能集約を構成できます。ただし、この方法をとった場合、そのアプリケーションは厳密なEJB 3.0仕様準拠ではなくなりますので注意してください。例21-1は、図21-1の各クラスのコード例を示します。ここでは、EJB 3.0の注釈とともにEclipseLinkによる拡張EJB 3.0仕様を利用し、埋込み可能なInfo
に、同じく埋込み可能なTeamInfo
とPersonalInfo
を埋め込んでいます。
例21-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; // EclipseLink 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;
...
}
集約として定義されたリレーショナル・ディスクリプタ(16.2.2項「ディスクリプタと継承」を参照)で継承を構成できますが、その場合は継承ツリー内のすべてのディスクリプタが集約である必要があります。集約ディスクリプタとクラス・ディスクリプタは、同じ継承ツリーに置くことはできません。
EJBプロジェクトではリレーショナル集約ディスクリプタを使用できますが、集約として定義されたリレーショナル・ディスクリプタ用にEJB情報を構成することはできません(16.2.3項「ディスクリプタとCMPおよびBMP」を参照)。
リレーショナル集約とEJB 3.0の使用方法の詳細は、21.2.1項「リレーショナル集約とネスト」を参照してください。
継承とは、導出されたクラスにそのスーパークラスの特性をどのように受け継がせるかを意味します。ディスクリプタを使用すると、リレーショナル・プロジェクトにおいてクラス間の継承リレーションシップを定義できます。
この項では、次の内容について説明します。
詳細は、16.3項「ディスクリプタと継承」を参照してください。
リレーショナル・プロジェクトの場合、TopLinkでは、継承階層内のすべてのクラスが、ルート・ディスクリプタに設定されているのと同じ主キーを持っていることが前提とされます。複数の主キーを持つデータ・ソース表現に関連付けられた子ディスクリプタには、ルートの主キーとローカルの主キーとの間のマッピングを定義する必要があります。
詳細は、119.2項「主キーの構成」を参照してください。
リレーショナル・プロジェクトでは、継承階層を単一表(21.3.2.1項「単一表の継承」を参照)にも複数表(21.3.2.2項「複数表の継承」を参照)にもマップできます。この選択肢を使用することで、アプリケーションに適した形で、格納効率とアクセス効率の間でバランスをとることができます。
この例では、複数レベルの継承を持つクラスを単一表に格納して、データベースのアクセス速度を最適化します。
図21-2に示すとおり、図21-1「ネストされた集約」の継承階層全体で同一の表を共有できます。FueledVehicle
の属性がNonFueledVehicle
にない場合でも、FueledVehicle
およびNonFueledVehicle
サブクラスは同じ表を共有できます。NonFueledVehicle
のインスタンスはデータベース・リソースを消費します。これは、データベースがNonFueledVehicleの使用されない部分の行に対しても領域を割り当ててしまうためです。とはいえ、この方法を使用すると、その他のFueledVehicle
情報を取得する際に別の表に結合する必要がなくなるため、アクセス時間が短縮されます。
図21-2に示したとおり、この方法ではクラス・インジケータ・フィールドを使用します。詳細は、16.3.1項「クラス・インジケータの指定方法」を参照してください。
この例では、複数レベルの継承を持つクラスを複数表に格納して、データベースのアクセス速度を最適化します。
図21-1「ネストされた集約」に示した継承階層において、追加の属性を必要とするサブクラスについては、スーパークラスの単一表ではなく複数表を使用します。これにより、データベース内で、実際には使用されないフィールドが存在することがなくなり、記憶域が最適化されます。ただし、TopLinkがオブジェクトをインスタンス化する場合には、複数表から読取りを行う必要があるため、パフォーマンスが低下します。TopLinkはまずクラス・インジケータ・フィールド(16.3.1項「クラス・インジケータの指定方法」を参照)を調べて、作成するオブジェクトのクラスを判別してから、そのクラスのディスクリプタを使用してサブクラスの表から属性を読み取ります。
図21-3は、TopLinkでのFUELEDVHCL
、CAR
、およびBICYCLE
表の実装を示します。すべてのオブジェクトはVEHICLE
表に格納されています。また、FueledVehicle
、Car
、Bicycle
の情報はセカンダリ表に格納されています。なお、NonFueledVehicle
クラスには、属性もリレーションシップもないため、セカンダリ表は不要です。
注意: 一般的に、複数表の継承の使用は、結合の頻度と複数表からのフェッチの頻度が高くなるため、非効率です。 |
ルートまたはブランチの継承ディスクリプタに、複数表にわたるサブクラスがある場合は、データベース・ビューを構成してすべてのサブクラス表を外部結合することにより、親ディスクリプタに対する問合せのパフォーマンスを最適化することができます。これにより、TopLinkはすべてのサブクラス・インスタンスを複数回ではなく1回の問合せでフェッチできるようになります。また、親クラスに対してカーソルまたは順序付けを使用した問合せも実行できます。
デフォルトで、TopLinkでは複数の問合せが実行され、複数表の継承階層が読み取られます。この方法が最も効率的な問合せ方法になる場合があります。また、TopLinkでは単一の外部結合問合せを使用した継承階層の問合せをサポートしています(119.19項「問合せでのサブクラス読取り機能の構成」参照)。
データベースのビューを、すべての表を外部結合または和集合を実行したディスクリプタに設定することもできます。詳細は、23.7項「複数表の情報の構成」を参照してください。