CMP エンティティ Bean のエンティティの関係は、ビジネス概念間の現実世界の依存関係をモデリングするために使用されます。このトピックでは、7 種類の関係の概要、およびこれらの各関係の EJB および基底のデータベース テーブルにおける実装の詳細について説明します。
詳細については、WebLogic Server ドキュメントの「コンテナ管理による関係 (CMR) の使用」および「コンテナ管理による関係 (CMR) の定義」を参照してください。ほとんどの WebLogic Server ドキュメントでは、これらの概念を、Workshop によって自動生成される EJB 記述子の観点から説明しています。
このトピックでは、以下の関係タイプについて個別に説明します。
1 対 1 の一方向の関係では、オブジェクト A はオブジェクト B に関係しており、さらにそのオブジェクト A があるとオブジェクト B への参照が見つかりますが、オブジェクト B があってもオブジェクト A への参照は見つかりません。こうした関係の例には、チケット カウンタから見た場合の、コンサートによく行く人とチケットの間の関係があります。コンサートによく行く人は、それぞれ正確に 1 枚のチケットを必要とし、各自のチケットへの参照を持つことになります。しかし、チケットがあってもコンサートによく行く人はわかりません。つまり、失われたチケットがチケット カウンタに戻って来ても、コンサートによく行く人をさかのぼって追跡することはできません。
次に、Concertgoer Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertgoerHasTicket", cmrField = "ticket", targetEjb = "Ticket", multiplicity = Relation.Multiplicity.ONE, name = "Concertgoer-Ticket") abstract public class Concertgoer extends GenericEntityBean implements EntityBean
次に、Ticket Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertgoerHasTicket", targetEjb = "Concertgoer", multiplicity = Relation.Multiplicity.ONE, name = "Concertgoer-Ticket") abstract public class Ticket extends GenericEntityBean implements EntityBean
Concertgoer EJB は、Ticket オブジェクトへの参照を設定および取得するための CMR フィールドを持つことになります。対照的に、Ticket から Concertgoer への参照はありません。つまり、特定のチケットがコンサートによく行く人に割り当てられているかどうか、および割り当てられている場合コンサートによく行く人は誰かということを調べる直接の方法はありません (これを調べるには、Concertgoer EJB に対してクエリを実行し、それぞれの参照されるチケットをチェックする必要があります)。
この特定の例では、Ticket オブジェクトは Concertgoer オブジェクトとは関係なく作成されると考えられます。CMR set メソッドは、Concertgoer を Ticket に関連付けるために使用されます。また、コンサートによく行く人がチケットを払い戻す (さらにチケット カウンタのデータベースから自身を削除する) 場合でも、Ticket オブジェクトは、再び販売される可能性があるので削除できません。顧客とその住所のように 1 対 1 の一方向の関係の依存性がより大きい場合には、Customer EJB は setAddress ビジネス メソッドを持つことができます。このメソッドはまず、新しい Address オブジェクトを作成し、次に CMR set メソッドを使用して参照を設定します (次のコードを参照)。
public void setAddress(String street, String apt, String city, String state, String zip) throws CreateException { Address currentAddress = this.getAddress( ); if (currentAddress == null) { // 顧客の現在の住所は不明 newAddress = addressHome.create(street, apt, city, state, zip); setAddress(newAddress); } else { // 顧客の現在の住所を更新する currentAddress.setStreet(street); currentAddress.setApt(apt); currentAddress.setCity(city); currentAddress.setState(state); currentAddress.setZip(zip); } }
最初に、CMR ゲット メソッドが現在のアドレスの参照を取得するために使用されていることに注目してください。住所が不明の場合、新しいアドレス オブジェクトが作成され、参照が設定されます。すでに住所への参照がある場合、住所オブジェクトは新しい住所を反映するように更新されます。
顧客がデータベースから削除されると、自宅の住所も削除されるようにできます。そのためには、このエンティティの関係に対してカスケード削除を指定します。これにより、顧客が削除されると自動的に自宅の住所も削除されます。詳細については、@Relation アノテーションを参照してください。
この関係の永続ストレージについては、一方のテーブルが外部キー カラム情報を持つ (他方の EJB の主キーのコピーを保持する) ことになります。通常、Concertgoer テーブルは、住所の主キー値を保持している「Ticket_Index」外部キー カラムを持ちます (Ticket EJB には主キー フィールドが 1 つだけ定義されており、複数の主キー カラムがある場合には、これらの値を保持する複数の外部キー カラムがあることを前提としています)。ただし、Ticket テーブルで Concertgoer の主キー値を保持することもできます。データベース テーブルでの実装に関係なく、EJB コンテナは関係が正しく表されることを保証します。
1 対 1 の双方向の関係では、オブジェクト A はオブジェクト B に関係しており、両方が相互に参照します。こうした関係の例には、チケット カウンタから見た場合の、コンサートによく行く人とクレジット カードの間の関係があります。コンサートによく行く人はそれぞれ (チケット購入用の) クレジット カードを 1 枚だけ持っており、クレジット カードをうっかりチケット カウンタに忘れてきた場合でもクレジット カードは所有者に戻ります。
次に、Concertgoer Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertgoerHasCreditCard", cmrField = "creditCard", targetEjb = "CreditCard", multiplicity = Relation.Multiplicity.ONE, name = "Concertgoer-CreditCard") abstract public class Concertgoer extends GenericEntityBean implements EntityBean
次に、CreditCard Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "CreditCardNamesConcertgoer", cmrField = "concergoer", targetEjb = "Concertgoer", multiplicity = Relation.Multiplicity.ONE, name = "Concertgoer-CreditCard") abstract public class CreditCard extends GenericEntityBean implements EntityBean
Concertgoer EJB は、CreditCard オブジェクトへの参照を設定および取得するための CMR フィールドを持つことになります。さらに、CreditCard オブジェクトは、Concertgoer オブジェクトへの参照を設定および取得するための CMR フィールドを持つことになります。また、この関係の双方向性は EJB コンテナによって保証されます。つまり、Concertgoer の CMR set メソッドを使用して CreditCard オブジェクトへの参照を設定すると、CreditCard オブジェクトの CMR フィールドは、この Concertgoer への参照を保持するように自動的に更新されます。同様に、あるオブジェクトで参照を変更または削除すると、この変更がもう一方のオブジェクトに自動的に適用されます。CMR フィールドが参照するオブジェクトの作成および削除に関する限りでは、先述の 1 対 1 の一方向の関係で説明したのと同じような設計上の考慮事項が適用されます。コンサートによく行く人に対して新しいクレジット カードを作成することについては、Concertgoer EJB は setCreditCard ビジネス メソッドを持つことができます。このメソッドは、新しいクレジット カード レコードを作成し、次に先述の節で示した setAddress メソッドと同様に、参照を設定します。その一方で CreditCard EJB が、CreditCard オブジェクトを作成し Concertgoer オブジェクトへの参照を設定する create メソッドを定義している場合は、その参照は ejbPostCreate の手順で設定される必要があります。この例については、後述の節を参照してください。
この関係の永続ストレージについては、データベース テーブルでの実装方法にかなりの柔軟性があります。使用できる方法の 1 つは、ConcertGoer テーブルのみが、クレジット カードの主キー値を保持している外部キー カラムを持つという方法です。この他にも使用できる方法があります。データベース テーブルでの実装に関係なく、EJB コンテナは関係が正しく表されることを保証します。
1 対多の一方向の関係では、オブジェクト A は多くのオブジェクト B に関係しており、オブジェクト A からすべてのオブジェクト B への参照はありますが、オブジェクト B からオブジェクト A への参照はありません。こうした関係の例には、コンサートによく行く人とコンサート後に購入された CD の間の関係があります。コンサートによく行く人は多くの CD を購入できますが、購入した CD をうっかりなくした場合、その後 CD が見つかっても、その CD からさかのぼってそれを購入したコンサートによく行く人を追跡することはできません。
次に、Concertgoer Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertgoerBoughtCDs", cmrField = "compactDisc", targetEjb = "CompactDisc", multiplicity = Relation.Multiplicity.ONE, name = "Concertgoer-CDs") abstract public class Concertgoer extends GenericEntityBean implements EntityBean
次に、CompactDisc Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "CDsBoughtByConcertgoer", targetEjb = "Concertgoer", multiplicity = Relation.Multiplicity.MANY, name = "Concertgoer-CDs") abstract public class CompactDisc extends GenericEntityBean implements EntityBean
Concertgoer EJB は、CD オブジェクトへの一連の参照を設定および取得するための CMR フィールドを持つことになります。対照的に、CD オブジェクトには CMR フィールドがありません。java.util.Collection または java.util.Set の選択は、同じオブジェクトに対して重複している可能性のある参照を持つ集合を保持すること、または重複した参照を持たないセットを保持すること、のいずれが設計の観点から意味を持つかによって決まります。
この特定の例では、Concertgoer オブジェクトは CD オブジェクトとは関係なく作成されると考えられます。新しい参照は Collection または Set の add メソッドを使用して CMR フィールドに追加され、参照は Collection または Set の remove メソッドを使用して、CD オブジェクトを削除することなく削除されます。バンドとそのレコーディングのように関係の依存性がより大きい場合には、Band EJB は addRecording ビジネス メソッドを持つことができます。このメソッドはまず、新しい Recording オブジェクトを作成し、次にそれを集合に追加します (次のコードを参照)。
public void addRecording(String recording) throws CreateException { Recording album = recordingHome.create(getBandName(), recording); Collection recordings = getRecordings(); if(album != null) { recordings.add(album); } }
このメソッドはまずアルバムを作成し、次に CMR get メソッドを使用してバンドの現在のレコーディングの集合を取得します。さらに、集合に新しいレコーディングを追加します。最後の手順がない場合、レコーディングは作成されますが、バンドによって参照されません。
Band オブジェクトがデータベースから削除される場合、そのレコーディングのカスケード削除が意味を持つかどうかは、表す現実世界のシナリオに応じて異なります。
この関係の永続ストレージについて使用できる唯一の実装は、コンサートによく行く人の主キー値を保持する外部キー カラムを CD テーブルが持つことです。お気付きのように、モデルと実際の実装が逆ですが、EJB コンテナは関係が正しく表されることを保証します。
注意 :現時点での WebLogic Server では、1 対多の関係を実装する結合テーブルの使用はサポートされていません。
1 対多の双方向の関係では、オブジェクト A は多くのオブジェクト B に関係しており、オブジェクト A からすべてのオブジェクト B への参照があり、各オブジェクト B はオブジェクト A を参照します。こうした関係の例には、コンサートによく行く人から見た場合の、コンサートによく行く人とクレジット カードの間の関係があります。コンサートによく行く人はそれぞれ多くのクレジット カードを持つことができ、クレジット カードをうっかり失った場合でもクレジット カードは所有者に戻ります。これは、コンサートによく行く人とクレジット カードの間の関係の 2 番目の例です。先述の節では、コンサートによく行く人ではなく、チケット カウンタから見た場合の、1 対 1 の双方向の関係が定義されました。
注意 :1 対多の双方向の関係と多対 1 の双方向の関係は概念的に同じであるため、1 種類の関係として示されています。
次に、Concertgoer Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertgoerHasCreditCards", cmrField = "creditCards", targetEjb = "CreditCard", multiplicity = Relation.Multiplicity.ONE, name = "Concertgoer-CreditCards") abstract public class Concertgoer extends GenericEntityBean implements EntityBean
次に、CreditCard Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "CreditCardsBelongToConcertgoer", cmrField = "concergoer", targetEjb = "Concertgoer", multiplicity = Relation.Multiplicity.MANY, name = "Concertgoer-CreditCards") abstract public class CreditCard extends GenericEntityBean implements EntityBean
Concertgoer EJB は、CreditCard オブジェクトへの一連の参照を設定および取得するための CMR フィールドを持つことになります。CreditCard オブジェクトは、ConcertGoer オブジェクトへの参照を設定および取得するための CMR フィールドを持つことになります。また、この関係の双方向性は EJB コンテナによって保証されます。つまり、EJB の一方への参照を設定または追加すると、もう一方の EJB に対して参照が自動的に更新されます。CMR フィールドが参照するオブジェクトの作成および削除に関する限りでは、先述の節で説明したのと同じような設計上の考慮事項が適用されます。
この関係の永続ストレージについて使用できる唯一の実装は、コンサートによく行く人の主キー値を保持する外部キー カラムを CreditCard テーブルが持つことです。
注意 :現時点での WebLogic では、1 対多の関係を実装する結合テーブルの使用はサポートされていません。
多対 1 の一方向の関係では、多くのオブジェクト A は 1 つのオブジェクト B に関係しており、各オブジェクト A からオブジェクト B への参照はありますが、オブジェクト B からオブジェクト A への参照はありません。こうした関係の例には、コンサートによく行く人から見た場合の、コンサートと会場の間の関係があります。数多くの様々なコンサートが同じ会場で行われますが、コンサートによく行く人は会場からコンサートを知ることについてはあまり関心がないと思われます。ただし、会場からコンサートを知ることがビジネス要件である場合は、これを 1 対多 (会場対コンサート) の双方向の関係としてモデリングすることになります。
次に、Venue Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "VenueHostsConcerts", targetEjb = "Concert", multiplicity = Relation.Multiplicity.ONE, name = "Venue-Concerts") abstract public class Venue extends GenericEntityBean implements EntityBean
次に、Concert Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertsOccurAtVenue", cmrField = "venue", targetEjb = "Venue", multiplicity = Relation.Multiplicity.MANY, name = "Venue-Concerts") abstract public class Concert extends GenericEntityBean implements EntityBean
Concert EJB は、Venue オブジェクトへの参照を設定および取得するための CMR フィールドを持つことになります。対照的に、Venue オブジェクトには CMR フィールドがありません。新しいコンサートがスケジュールされると、この時点で会場を知らせる必要があると思われます。つまり、Concert オブジェクトを作成する場合には、作成手順の一部として Venue オブジェクトへの参照を設定する必要があります (次の例を参照)。
abstract public class ConcertBean extends GenericEntityBean implements EntityBean { ... public Integer ejbCreate(String bandName, Venue theVenue) { setBandName(bandName); return null; } public void ejbPostCreate(String bandName, Venue theVenue) { setVenue(theVenue); } ...
ejbCreate は演奏するバンド名を設定し、その一方で Venue オブジェクトへの参照が、対応する ejbPostCreate メソッドで設定されています。参照は常に ejbPostCreate メソッドで設定される必要があります。参照の設定に必要な主キーはオブジェクト作成後まで使用できないからです。
カスケード削除は、この関係についてはあまり意味を持ちません。つまり、1 つのコンサートを削除しても、その他の多くのコンサートがこの会場にスケジュールされている場合には会場の破棄にはつながらないはずです。
この関係の永続ストレージについて使用できる唯一の実装は、会場の主キー値を保持する外部キー カラムを Concert テーブルが持つことです。
注意 :現時点での WebLogic では、1 対多の関係を実装する結合テーブルの使用はサポートされていません。
多対多の一方向の関係では、オブジェクト A は多くのオブジェクト B に関係しており、オブジェクト B は多くのオブジェクト A に関係しています。各オブジェクト A からオブジェクト B への参照はありますが、オブジェクト B からオブジェクト A への参照はありません。こうした関係の例には、コンサートによく行く人とコンサートの間の関係があります。コンサートによく行く人は数多くのコンサートに行きます。各コンサートは多くのコンサートによく行く人を魅了します。コンサートによく行く人がいるとその人が行ったコンサートを知ることができますが、コンサートからそのコンサートに来ていた特定のコンサートによく行く人を知りたいとは思わないはずです。
次に、Concertgoer Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertgoerAttendsConcerts", cmrField = "concerts", targetEjb = "Concert", multiplicity = Relation.Multiplicity.MANY, name = "Concertgoer-Concerts") abstract public class Concertgoer extends GenericEntityBean implements EntityBean
次に、Concert Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "ConcertsHaveManyConcertgoers", targetEjb = "Concertgoer", multiplicity = Relation.Multiplicity.MANY, name = "Concertgoer-Concerts") abstract public class Concert extends GenericEntityBean implements EntityBean
Concertgoers EJB は、Concert オブジェクトへの一連の参照を設定および取得するための CMR フィールドを持つことになります。対照的に、Concert オブジェクトには CMR フィールドがありません。CMR フィールドの操作、および CMR フィールドが参照するオブジェクトの作成と削除に関する限りでは、先述の節で説明したのと同じような設計上の考慮事項が適用されます。カスケード削除は、多対多の関係については通常、意味を持ちません。
この関係の永続ストレージについては、結合テーブルが使用されます。結合テーブル内の各レコードには 2 つの外部キー カラムがあります。1 つはコンサートによく行く人の主キー値を保持し、もう 1 つはコンサートの主キー値を保持します (両方の EJB は 1 つのユニークな主キー フィールドを持つように定義されていることを前提としています)。
多対多の双方向の関係では、オブジェクト A は多くのオブジェクト B に関係しており、オブジェクト B は多くのオブジェクト A に関係しています。各オブジェクト A からオブジェクト B への参照があり、同様に各オブジェクト B からオブジェクト A への参照があります。こうした関係の例には、乗客とフライトの間の関係があります。乗客は複数のフライトを利用でき、フライトは通常、複数の乗客によって予約されます。乗客がいればフライトがわかりますし、フライトがわかれば飛行機に乗るべき乗客を正確に知ることができます。
次に、Passenger Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "PassengersTakeFlights", cmrField = "flights", targetEjb = "Flight", multiplicity = Relation.Multiplicity.MANY, name = "Paesengers-Flights") abstract public class Passenger extends GenericEntityBean implements EntityBean
次に、Flight Bean の @Relation アノテーションの例を示します。
@Relation(roleName = "FlightsHaveManyPassengers", cmrField = "passengers", targetEjb = "Passenger", multiplicity = Relation.Multiplicity.MANY, name = "Passengers-Flights") abstract public class Flight extends GenericEntityBean implements EntityBean
Passenger EJB は、Flight オブジェクトへの一連の参照を設定および取得するための CMR フィールドを持つことになります。Flight EJB は、Passenger オブジェクトへの一連の参照を設定および取得するための CMR フィールドを持つことになります。CMR フィールドの操作、および CMR フィールドが参照するオブジェクトの作成と削除に関する限りでは、先述の節で説明したのと同じような設計上の考慮事項が適用されます。この特定の例では、1 人の乗客が何人かの乗客のために 1 つのフライトを同時に予約できます。Collection または Set の addAll メソッドを使用して、複数の参照を追加できます。また、双方向性は EJB コンテナによって保証され、カスケード削除は、多対多の関係については通常、意味を持ちません。
この関係の永続ストレージについては、結合テーブルが使用されます。結合テーブル内の各レコードには 2 つの外部キー カラムがあります。1 つはコンサートによく行く人の主キー値を保持し、もう 1 つはコンサートの主キー値を保持します (両方の EJB は 1 つのユニークな主キー フィールドを持つように定義されていることを前提としています)。