ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Application Development FrameworkによるFusion Webアプリケーションの開発
12c (12.1.2)
E48099-02
  目次へ移動
目次

前
 
次
 

7 多相ビュー・オブジェクトの定義

この章では、ADFビジネス・コンポーネントの継承を使用して、Oracle ADFアプリケーションで複数のビュー行型を公開するADFビュー・オブジェクトを作成する方法を説明します。また、この章では、エンティティ・オブジェクトの継承を使用するかわりの方法として、ビュー・オブジェクトの継承階層を定義して異種ビュー行を生成する方法についても説明します。

この章には次の項が含まれます:

7.1 多相ビュー・オブジェクトについて

ビュー・オブジェクトでは、ベース・エンティティ・オブジェクトによって表現される表を作成できます。一般に、エンティティ・ベースのビュー・オブジェクトを作成するときには、Domestics(国内の顧客に関連する固有の属性を含むと考えられる)など、単一の型を持つエンティティ行を操作するようにビュー・オブジェクトを作成します。また、場合によっては、同じ行セットでエンティティ・オブジェクト継承階層に基づいて行を問い合せて更新することもあります。たとえば、同じ行セットで、CustomersDomesticsおよびInternationalsの各エンティティ・オブジェクトの継承階層に共通する属性を処理することがあります。このようなビュー・オブジェクトは多相ビュー・オブジェクトと呼ばれます。クライアントで多相ビュー・オブジェクトが適切に使用されるようにするために、ビュー・オブジェクトでは、異種混在の行セット内の各行について、委譲先のエンティティ・オブジェクトを認識しておく必要があります。行の型を識別するために、多相ビュー・オブジェクトは、各行の対応する表を特定する識別子属性に依存しています。

ADFビジネス・コンポーネントでは、多相ビュー・オブジェクトを作成する2つの方法をサポートしています。多相ビュー・オブジェクトを作成する方法は、次のとおりです。

最初のタイプの多相ビュー・オブジェクト(エンティティ・サブタイプの継承に基づくもの)を使用する場合、クライアントにエンティティ・オブジェクト慣用名の様々なサブタイプが公開されることはありません。クライアントが関係する範囲では、ビュー・オブジェクトの結果セットの各行は同じ属性セットと同じ行の型を持ちます。このようになるのは、ADFビジネス・コンポーネントによって、識別子属性の値に基づいて必ず正しいエンティティ・オブジェクト行サブタイプが作成されるようになっているからです。つまり、多相エンティティ・オブジェクトの慣用名を使用することで、ビュー行の型は一定でありながら、ビュー行のエンティティ行の部分でのみ型が変更されるようになっています。

2番目のタイプの多相ビュー・オブジェクト(ビュー・オブジェクト階層の継承に基づくもの)では、結果に1つ以上のビュー行サブタイプを含めることができるようにアプリケーション・モジュールを構成できます。クライアントに表示されるビュー行の型に異なる複数のサブタイプを生成できるのは、多相ビュー行を使用した場合のみです。また、多相エンティティ・オブジェクトの慣用名の場合とは異なり、ビュー行のサブタイプに属性を追加してクライアントに公開できることも、多相ビュー行のみの特徴です。


注意:

この項で説明する例を試すには、4.19項「ビジネス・ドメイン・レイヤーでの継承の使用」で使用したものと同じAdvancedEntityExamplesワークスペースのInheritanceAndPolymorphicQueriesプロジェクトを使用します。


7.1.1 多相エンティティ・オブジェクトの慣用名と多相ビュー行の慣用名

どちらか一方のポリモフィズムを使用するか、2つを組み合せることができます。

通常は一緒に使用する方が役に立ちますが、ビュー行ポリモフィズム機能と多相エンティティ・オブジェクト慣用名機能は異なるものであり、個別に使用できます。特に、ビュー行ポリモフィズムの機能は、読取り専用ビュー・オブジェクトにも、エンティティ・ベースのビュー・オブジェクトにも使用できます。両方のメカニズムを組み合せると、多相のエンティティ行部分とビュー行型の両方を持つことができます。

ビュー・オブジェクトまたはエンティティ・オブジェクトでビュー行ポリモフィズムを使用するには、それぞれに個別の識別子属性プロパティを構成する必要があることに注意してください。これが必要になるのは、読取り専用ビュー・オブジェクトには、識別子情報を推測する関連エンティティ・オブジェクトの慣用名が含まれていないためです。

識別子属性が1レベルを超えない深さで定義されるビュー・オブジェクトを必要とする多相ビュー・オブジェクトの場合は、制限があります。プロジェクトで行のサブタイプを指定する識別子属性を持つ多相ビュー・オブジェクを定義する場合がありますが、このとき別のビュー・オブジェクトを使用して、最初の多相ビュー・オブジェクトに基づいてさらにサブ行を指定すると、サブ行の表示でエラーが発生します。多相ビュー・オブジェクトを作成する場合は、識別子属性の定義を1レベルに制限してください。

まとめると、ビュー行のポリモフィズムを使用する場合は、次の手順を実行します。

  1. 継承階層のルート・ビュー・オブジェクトのビュー・オブジェクト・レベルで、識別子にする属性を構成します。

  2. 継承されるビュー・オブジェクトの階層を定義し、階層内の各ビュー・オブジェクトのビュー・オブジェクト・レベルの識別子属性に、サブタイプ値プロパティとして個別値(ビュー・オブジェクト定義ファイルの属性のDefaultValueとして識別される)を指定します。

  3. アプリケーション・モジュールのサブタイプのリストに、この階層内にあるサブクラス化されたビュー・オブジェクトのリストを入れます。

一方、多相エンティティ・オブジェクトの慣用名を含むビュー・オブジェクトを作成するには、次のことを行います。

  1. 継承階層のルート・エンティティ・オブジェクトのエンティティ・オブジェクト・レベルで、識別子にする属性を構成します。

  2. 継承されるエンティティ・オブジェクトの階層を定義し、階層内のエンティティ・オブジェクトのそれぞれでオーバーライドを行って、そのエンティティ・オブジェクト・レベルの識別子属性のサブタイプ値プロパティに個別の値を設定します。

  3. ビュー・オブジェクトのサブタイプのリストに、サブクラス化されたエンティティ・オブジェクトのリストを入れます。

7.2 多相エンティティ・オブジェクトの慣用名での作業

多相エンティティ・オブジェクトの慣用名とは、継承階層のベース・エンティティ・オブジェクトを参照し、そのエンティティのサブタイプも処理するように構成されているものです。図7-1は、多相エンティティ・オブジェクトの慣用名でビュー・オブジェクトを使用した結果を示しています。エンティティ・ベースのCustomerListビュー・オブジェクトには、プライマリ・エンティティ・オブジェクトの慣用名としてCustomersエンティティ・オブジェクトがあります。ビュー・オブジェクトは、データベースから取得された各行を、Customersの様々なサブタイプに固有の属性を持つエンティティ行に分割します。識別子属性の値の検査に基づいて、適切なエンティティ行サブタイプを作成します。たとえば、CustomerListの問合せで、国内企業ABC Companyの1行と国際企業Simms Athleticの1行が取得された場合、基礎になっているエンティティ行は図で示されているようになります。

図7-1 多相エンティティ・オブジェクトの慣用名を持つビュー・オブジェクトによるエンティティ・サブタイプの処理

エンティティ・サブタイプの流れ

7.2.1 多相エンティティ・オブジェクトの慣用名を持つビュー・オブジェクトを作成する方法

多相エンティティ・オブジェクトの慣用名で作成するビュー・オブジェクトは、ベース・エンティティ・オブジェクトおよびサブタイプ・エンティティの1つ以上の属性を継承できます。エンティティ・オブジェクトから選択する属性は、ビュー・オブジェクト属性定義によってオーバーライドされます。エンティティ・ベースのビュー・オブジェクトが識別子属性を持つエンティティ・オブジェクトを参照していると、JDeveloperはその識別子属性も(主キー属性に加えて)問合せに含まれるようにします。

始める前に:

多相ビュー・タイプに関する知識が役立つ場合があります。詳細は、7.1項「多相ビュー・オブジェクトについて」を参照してください。

次のタスクを完了する必要があります。

  1. 4.2.2項「エンティティの作成ウィザードで単一のエンティティ・オブジェクトを作成する方法」の説明に従って、多相エンティティ・オブジェクトの慣用名の継承元ベース・エンティティ・オブジェクトを作成します。

  2. 4.10.14項「エンティティ・オブジェクト継承階層の識別子属性の設定方法」の説明に従って、ベース・エンティティ・オブジェクトを拡張して、多相エンティティ・オブジェクトの慣用名を作成し、エンティティ行サブタイプの基礎となる識別子属性を指定します。

  3. ベース・エンティティ・オブジェクトからエンティティ・ベースのビュー・オブジェクトを作成し、各多相エンティティ・オブジェクトの慣用名に対して作成するサブタイプ・ビュー・オブジェクトに共通する属性を選択します。ベース・ビュー・オブジェクトは、サブタイプ・ビュー・オブジェクトを作成するために使用されます。エンティティ・ベースのビュー・オブジェクトの作成の詳細は、5.2.1項「エンティティ・ベースのビュー・オブジェクトの作成方法」を参照してください。

多相エンティティ・オブジェクトの慣用名でビュー・オブジェクトを作成するには:

  1. 「アプリケーション」ウィンドウでデータ・モデル・プロジェクトを右クリックし、「新規」「ビュー・オブジェクト」の順に選択します。

  2. ビュー・オブジェクトの作成ウィザードで、ビュー・オブジェクトの名前を指定し、「拡張」フィールドの横にある「参照」をクリックします。

    たとえば、DomesticsInternationalsの各サブタイプ・エンティティ・オブジェクトの多相エンティティ・オブジェクト慣用名を使用したビュー・オブジェクト作成をサポートするために、データ・モデル・プロジェクトでベースのCustomersエンティティ・オブジェクトを定義できます。各多相エンティティ・オブジェクト慣用名のビュー・オブジェクトを作成するときには、DomesticListInternationalListなどの名前でビュー・オブジェクトを作成できます。

  3. 「親の選択」ダイアログで、ベース・エンティティ・オブジェクトから作成したエンティティ・ベースのビュー・オブジェクトを選択して、「OK」をクリックします。

    たとえば、サブタイプ・エンティティ・オブジェクトDomesticsに対するビュー・オブジェクトDomesticListを作成する場合は、拡張するビュー・オブジェクトとして、TheCustomerを選択します。

  4. ビュー・オブジェクト作成ウィザードで「次」をクリックして、「選択済」リストにベース・エンティティ・オブジェクトがすでに表示され、Extendedとラベルが付けられていることを確認します(図7-2を参照)。

    図7-2 ベース・エンティティが選択されたビュー・オブジェクト

    ベース・エンティティ・オブジェクト選択済
  5. 「エンティティ・オブジェクト」ページの「使用可能」リストで、ベース・エンティティ・オブジェクトから作成したエンティティ・サブタイプを探して、「OK」をクリックします。

    たとえば、ベース・エンティティ・オブジェクトCustomersに対するビュー・オブジェクトDomesticListを作成する場合は、エンティティ・サブタイプとしてDomesticsを選択します。

  6. 「ビジネス・コンポーネント」ダイアログで、「OK」をクリックしてビュー・オブジェクトのエンティティ・オブジェクトの慣用名をオーバーライドします。

    ビジネス・コンポーネント」ダイアログで、ベース・エンティティ・オブジェクトの慣用名の属性をエンティティ・サブタイプでオーバーライドする旨の警告が示されます(図7-3を参照)。

    図7-3 多相エンティティ・サブタイプが選択されたビュー・オブジェクト

    サブタイプによるエンティティのオーバーライド
  7. 「選択済」リストで、オーバーライドされたエンティティ・オブジェクトを選択して、「サブタイプ」をクリックします。

  8. 「サブタイプの選択」ダイアログで、目的のエンティティ・サブタイプを「選択済」から選択し、「OK」をクリックします。

    たとえば、DomesticListビュー・オブジェクト用にエンティティ・サブタイプDomesticsを選択します(図7-4を参照)。

    図7-4 エンティティ・サブタイプが選択されたビュー・オブジェクト

    「サブタイプの選択」ダイアログ
  9. ビュー・オブジェクトの作成ウィザードの「エンティティ・オブジェクト」ページで、「次へ」をクリックし、ウィザードの「属性」ページで必要な属性をエンティティ・サブタイプから「選択済」リストに移動します。

    たとえば、DomesticListビュー・オブジェクト用に、エンティティ・サブタイプDomesticsからState属性を選択します(図7-5を参照)。

    図7-5 エンティティ・サブタイプの属性が追加されたビュー・オブジェクト

    サブタイプから属性を選択
  10. ウィザードへの入力を完了させて、「終了」をクリックします。

    概要エディタの「エンティティ・オブジェクト」ページに、選択されたエンティティ・オブジェクトとエンティティ・サブタイプ・オーバーライドが表示されます。たとえば、DomesticListビュー・オブジェクトの概要エディタに、Customers (Domestics): overriddenのように、オーバーライドされたエンティティ・オブジェクトとカッコで囲まれたサブタイプが表示されます(図7-6を参照)。

    図7-6 ビュー・オブジェクト・エディタでのエンティティ・サブタイプ・オーバーライド

    ビュー・オブジェクト・エディタでのサブタイプ・オーバーライド
  11. この手順を繰り返して、ベース・エンティティ・オブジェクトに作成した追加の多相エンティティ・オブジェクトの慣用名のビュー・オブジェクトを作成します。

7.2.2 多相エンティティ・オブジェクトの慣用名によりビュー・オブジェクトを作成すると行われる処理

多相エンティティ・オブジェクトの慣用名でエンティティ・ベースのビュー・オブジェクトを作成すると、JDeveloperにより、許可されるエンティティ・サブタイプに関する情報がビュー・オブジェクトのXMLドキュメントに追加されます。たとえば、前述のDomesticListビュー・オブジェクトを作成すると、許可されるサブタイプ・エンティティ・オブジェクトの名前が次のようなAttrArrayタグに記録されます。

<ViewObject Name="DomesticList" ... >
   <EntityUsage Name="TheCustomer"
                Entity="oracle.summit.model.polymorphicsample.Customers" >
   </EntityUsage>
...
   <AttrArray Name="EntityImports">
      <Item Value="oracle.summit.model.polymorphicsample.Domestics" />
      <Item Value="oracle.summit.model.polymorphicsample.Internationals" />
   </AttrArray>
   <!-- etc. -->
</ViewObject>

7.2.3 エンティティ・オブジェクトの慣用名に関する必知事項

多相エンティティ・オブジェクトの慣用名を使用する場合は、識別子属性による問合せのフィルタリングによって期待するサブタイプのみが含まれるように、次のベスト・プラクティスに従うことをお薦めします。

7.2.3.1 問合せでは期待するエンティティ・サブタイプに行を制限する必要がある

ビュー・オブジェクトが階層で使用可能なエンティティ・サブタイプのサブセットのみを使用する場合は、識別子列が期待するエンティティ・タイプと一致する行のみを返すように問合せを制限する適切なWHERE句を含める必要があります。問合せでサブタイプのフィルタリングを行うときには、識別子属性のみに依存しないでください。問合せを絞り込むための属性を追加しないと、ビュー・オブジェクトでは事実上すべての行に問合せが実行され、どの識別子の値にも一致しない列がクライアントで破棄されることになります。

7.2.3.2 委譲を使用したビュー行での選択したエンティティ・メソッドの公開

設計上、クライアントはエンティティ・オブジェクトを直接使用しません。かわりに、当面のタスクに関連する情報のセットを表す適切なビュー・オブジェクトのビュー行を通して、間接的にエンティティ・オブジェクトを使用します。ビュー・オブジェクトは、当面のタスクに関連する1つまたは複数のエンティティ・オブジェクトの基礎となる属性の特定のセットを公開できるのと同じように、これらのエンティティから選択されたメソッドのセットも公開できます。そのためには、カスタム・ビュー行のJavaクラスを有効にし、次のビュー行クラスでメソッドを記述します。

  • ビュー行で生成されるエンティティ・アクセッサを使用して基礎となる適切なエンティティ行にアクセス

  • そのメソッドの呼出し

たとえば、Customersエンティティ・オブジェクトに、そのCustomersImplクラスのperformCustomerFeature()メソッドが含まれているとします。このメソッドをCustomerListビュー行でクライアントに公開するには、カスタム・ビュー行のJavaクラスを有効にし、例7-1で示されているメソッドを記述します。JDeveloperは、エンティティ・オブジェクトの慣用名の別名に基づいて、関係する各エンティティ・オブジェクトの慣用名に対するビュー行クラスで、エンティティ・アクセッサ・メソッドを生成します。CustomerListビュー・オブジェクトでのCustomersエンティティの別名はTheCustomerであるため、そのエンティティ・オブジェクトの慣用名に関係するエンティティ行部分を返すためのgetTheCustomer()メソッドを生成します。

例7-1 選択したエンティティ・オブジェクト・メソッドの委譲によるビュー行での公開

// In CustomerListRowImpl.java
public void performCustomerFeature() {
  getTheCustomer().performCustomerFeature();
}

ビュー行のperformCustomerFeature()メソッドのコードでは、このgetTheCustomer()メソッドを使用して基礎となるCustomersImplエンティティ行クラスにアクセスし、そのperformCustomerFeature()メソッドを呼び出します。このコーディング・スタイルは委譲と呼ばれるもので、ビュー行メソッドはそのメソッドの1つの実装を、基礎となるエンティティ・オブジェクトの対応するメソッドに委譲します。多相エンティティ・オブジェクトの慣用名のあるビュー行で委譲が使用されると、委譲されたメソッド呼出しは、基礎となる適切なエンティティ行サブタイプによって処理されます。つまり、CustomersImplクラス、DomesticsImplクラスおよびInternationalsImplクラスが異なる方法でperformCustomerFeature()メソッドを実装している場合は、現在行のエンティティ・サブタイプに応じて、適切な実装が使用されます。

クライアント行インタフェースでこのメソッドを公開すると、クライアント・プログラムは、カスタム行インタフェースを使用して、特定のビュー行でカスタム・ビジネス機能を呼び出すことができます。例7-2は、TestEntityPolymorphismクラスのコード行を示しています。CustomerListビュー・オブジェクト・インスタンスのすべての行を反復し、各行をカスタムのCustomerListRowインタフェースにキャストして、performCustomerFeature()メソッドを呼び出しています。

例7-2 エンティティ・オブジェクトに委譲するビュー行メソッドの呼出し

CustomerList customerlist = (CustomerList)am.findViewObject("CustomerList");
customerlist.executeQuery();
while (customerlist.hasNext()) {
  CustomerListRow customer = (CustomerListRow)customerlist.next();
  System.out.print(customer.getEmail()+"->");
  customer.performCustomerFeature();
}

例7-2のクライアント・コードを実行すると、次のような出力が生成されます。

austin->## performCustomerFeature as Domestics
hbaer->## performCustomerFeature as Internationals
:
sking->## performCustomerFeature as Domestic
:

Customersエンティティに関連する行では、CustomersImplクラスのperformCustomerFeature()メソッドが使用されたことを確認するメッセージが表示されます。Domesticsエンティティに関連する行とInternationalsエンティティに関連する行では異なるメッセージが表示され、DomesticsImplクラスとInternationalsImplクラスが継承されたperformCustomerFeature()メソッドに関して持っている異なる実装がはっきり示されます。

7.2.3.3 目的のエンティティ・サブタイプでの新しい行の作成

多相エンティティ・オブジェクトの慣用名のあるビュー・オブジェクトでは、新しいビュー行を作成すると、それにはベース・エンティティ・オブジェクトの慣用名と一致する型を持つ新しいエンティティ行部分が含まれます。かわりにいずれかのエンティティ・サブタイプで新しいビュー行を作成するには、createAndInitRow()メソッドを使用します。例7-3は、CustomerListビュー・オブジェクトのJavaクラスにおける2つのカスタム・メソッドを示しています。これらのメソッドでは、createAndInitRow()を使用して、クライアントがDomesticsまたはInternationalsサブタイプのエンティティ行を持つ新しい行を作成できるようにしています。createAndInitRow()を使用するには、例で示されているように、NameValuePairsオブジェクトのインスタンスを作成し、それに識別子属性の適切な値を設定します。次に、そのNameValuePairscreateAndInitRow()メソッドに渡し、指定した識別子属性の値に基づいて、適切なエンティティ行サブタイプを持つ新しいビュー行を作成します。

例7-3 エンティティ・サブタイプを持つ新しい行を作成するためのカスタム・メソッドの公開

// In CustomerListImpl.java
public CustomerListRow createCustomersRow() {
  NameValuePairs nvp = new NameValuePairs();
  nvp.setAttribute("CustomerTypeCode","DOMESTIC");
  return (CustomerListRow)createAndInitRow(nvp);
}
public CustomerListRow createInternationalsRow() {
  NameValuePairs nvp = new NameValuePairs();
  nvp.setAttribute("CustomerTypeCode","INTERNATIONAL");
  return (CusotmersListRow)createAndInitRow(nvp);
} 

このようなメソッドをビュー・オブジェクトのカスタム・インタフェースで公開すると、実行時に、クライアントはそれを呼び出して、適切なエンティティ・サブタイプを持つ新しいビュー行を作成できます。例7-4は、TestEntityPolymorphismクラスのこの機能に関連する行を示しています。最初に、createRow()メソッド、createDomesticsRow()メソッドおよびcreateInternationalsRow()メソッドを使用して、3つの新しいビュー行を作成します。次に、新しい行のそれぞれで、CustomerListRowカスタム・インタフェースからperformCustomerFeature()メソッドを呼び出します。

各行は期待したとおりに関連するエンティティ行のサブタイプに固有の方法でメソッドを処理し、結果を生成します。

## performCustomerFeature as Customer
## performCustomerFeature as Domestic
## performCustomerFeature as International

例7-4 異なるエンティティ・サブタイプでの新しいビュー行の作成

// In TestEntityPolymorphism.java
CustomerListRow newCustomer = (CustomerListRow)CustomerList.createRow();
CustomerListRow newDomestic  = Customerlist.createDomesticsRow();
CustomerListRow newInternational = Customerlist.createInternationalsRow();
newCustomer.performCustomerFeature();
newDomestic.performCustomerFeature();
newInternational.performCustomerFeature();

7.3 多相ビュー行関連の作業

7.2項「多相エンティティ・オブジェクトの慣用名での作業」で示されている例では、「舞台裏」であるエンティティ・オブジェクト・レベルでポリモフィズムが発生していました。クライアント・コードは同じCustomerListRowインタフェースを使用してすべてのビュー行を処理するので、Domesticsエンティティ・オブジェクトに基づく行と、Customersエンティティ・オブジェクトに基づく行を区別することはできません。コードは、基礎となるエンティティ・サブタイプのすべての型に共通するビュー行属性とメソッドの同じセットを使用して、すべてのビュー行を処理します。

多相ビュー行をサポートするようにビュー・オブジェクトを構成すると、クライアントは、行の型に固有のビュー行インタフェースを使用して、異なる型のビュー行を処理できます。このようにすると、クライアントは、必要に応じて、特定のサブタイプに固有のビュー属性にアクセスしたり、ビュー行メソッドを呼び出したりできます。図7-7は、前述のCustomerListの例に対してこの機能を有効にするビュー・オブジェクトの階層を示しています。DomesticListInternationalListは、ベース(または親)のCustomerListビュー・オブジェクトを拡張した子ビュー・オブジェクトです。それぞれが、エンティティ・オブジェクトの慣用名として保持する、Customersのそのサブタイプに固有の追加属性を含んでいることに注意してください。DomesticListにはState追加属性が含まれ、InternationalListにはState属性はないものの、Language属性が含まれています。ビュー行ポリモフィズム用に構成されている場合、クライアントは次のものを使用してCustomerListビュー・オブジェクトの結果を処理できます。

これにより、クライアントは、特定のサブタイプのビュー行に固有の追加属性とビュー行メソッドにアクセスできます。

図7-7 ビュー行ポリモフィズムを有効にするビュー・オブジェクト・サブタイプの階層

行のポリモフィズムを有効にするサブタイプ階層

7.3.1 多相ビュー行を持つビュー・オブジェクトの作成方法

多相ビュー行によって作成するビュー・オブジェクトは、それぞれに固有のベース・エンティティ・オブジェクトを持つビュー・オブジェクトの階層から、1つ以上の属性を継承できます。拡張されたビュー・オブジェクトから選択する属性は、親ビュー・オブジェクトの多相ビュー行定義によってオーバーライドされます。エンティティ・ベースのビュー・オブジェクトが識別子属性を持つエンティティ・オブジェクトを参照していると、JDeveloperはその識別子属性も(主キー属性に加えて)問合せに含まれるようにします。

始める前に:

多相ビュー・タイプに関する知識が役立つ場合があります。詳細は、7.3項「多相ビュー行関連の作業」を参照してください。

多相ビュー行を持つビュー・オブジェクトを作成するには:

  1. 「アプリケーション」ウィンドウで、ベース・ビュー・オブジェクトにするビュー・オブジェクトをダブルクリックします。

    たとえば、図7-7では、CustomerListビュー・オブジェクトがベース・ビュー・オブジェクトになっています。

  2. 概要エディタで「属性」ナビゲーション・タブをクリックし、ビュー行の識別子属性を選択して、「詳細」タブをクリックします。

  3. 「詳細」ページで、識別子属性にデフォルト値を指定し、「多相識別子」チェック・ボックスを選択して、使用するビュー行インタフェースを識別するものとして属性をマークします。

    ベース・ビュー・オブジェクトのビュー行インタフェースが使用するものと予想される属性値に一致する値を、「サブタイプ値」フィールドで指定する必要があります。たとえば、CustomerListビュー・オブジェクトでは、CustomerTypeCode属性を識別子属性としてマークし、デフォルトのサブタイプ値をCUSTOMERにします。

  4. ベース・ビュー・オブジェクトのカスタム・ビュー行クラスを有効にし、少なくとも1つのメソッドをクライアント行インタフェースで公開します。このメソッドとしては、ビュー行属性アクセッサ・メソッドの1つまたは全部、および任意のカスタム・ビュー行メソッドを使用できます。

  5. ベース・ビュー・オブジェクトを拡張する新しいビュー・オブジェクトを作成します。

    たとえば、図7-7では、DomesticListがベースのCustomerListビュー・オブジェクトを拡張しています。

  6. 拡張されたビュー・オブジェクトのカスタム・ビュー行クラスを有効にします。

    妥当な場合は、新しいカスタム・ビュー行メソッドを追加するか、または親ビュー・オブジェクトの行クラスから継承するカスタム・ビュー行メソッドをオーバーライドします。

  7. 拡張されたビュー・オブジェクトの識別子属性に個別の値を設定します。

    DomesticListビュー・オブジェクトは、CustomerTypeCode識別子属性にDOMESTICという値を設定しています。

  8. 必要に応じて、手順5から7を繰り返し、他の拡張されたビュー・オブジェクトを追加します。

    たとえば、InternationalListは、CustomerListを拡張する2番目のビュー・オブジェクトです。このオブジェクトでは、CustomerTypeCode識別子属性に値INTERNATIONALを設定しています。

ビュー・オブジェクトの階層を設定した後、ビュー行ポリモフィズムに参加するビュー・オブジェクト・サブタイプのリストを定義する必要があります。これは次のようにして行います。

  1. 階層内のビュー・オブジェクトの各型のインスタンスを、アプリケーション・モジュールのデータ・モデルに追加します。

    たとえば、CustomersModuleアプリケーション・モジュールには、CustomerListDomesticListおよびInternationalListの各ビュー・オブジェクトのインスタンスがあります。

  2. アプリケーション・モジュールの概要エディタで「データ・モデル」ナビゲーション・タブをクリックし、「サブタイプ」ボタンをクリックします。

  3. 表示される「サブタイプ」ダイアログで、ビュー行ポリモフィズムに加えるビュー・オブジェクト・サブタイプを「使用可能」から「選択済」リストに移動し、「OK」をクリックします。

7.3.2 多相ビュー行に関する必知事項

多相ビュー行を操作する場合は、行の型を扱って、表示する属性をカスタマイズするか、ビュー行のエンティティ・サブタイプに固有のメソッドに委譲を行うことができます。

7.3.2.1 拡張されたビュー・オブジェクトでのサブタイプ固有の属性の選択

拡張されたビュー・オブジェクトを作成すると、そのオブジェクトは親のエンティティ・オブジェクトの慣用名を継承します。親のビュー・オブジェクトのエンティティ・オブジェクトの慣用名がドメイン・レイヤーのサブタイプを持つエンティティ・オブジェクトに基づいている場合は、継承した親のエンティティ・オブジェクトの慣用名型ではなく、これらのサブタイプのいずれかを拡張されたビュー・オブジェクトが使用するようにする場合があります。このようにするには2つの理由があります。

  • エンティティ・サブタイプに固有の属性を選択するため

  • エンティティ・サブタイプに固有のメソッドに委譲するビュー行メソッドを作成できるようにするため

これを行うには、継承されたエンティティ・オブジェクトの慣用名をオーバーライドして、目的のエンティティ・サブタイプを参照する必要があります。そのためには、拡張されたビュー・オブジェクトの概要エディタで次の手順を行います。

ビュー・オブジェクトのエンティティ・オブジェクト慣用名をオーバーライドするには:

  1. 「アプリケーション」ウィンドウで、オーバーライドするエンティティ・オブジェクトの慣用名を含むビュー・オブジェクトをダブルクリックします。

  2. 概要エディタで「エンティティ・オブジェクト」ナビゲーション・タブをクリックして、拡張されたエンティティ・オブジェクトの慣用名を使用していることを確認します。

    たとえば、DomesticListビュー・オブジェクトを拡張するDomesticListビュー・オブジェクトを作成するときは、最初、「選択済」リストに、TheCustomerという別名を使用するエンティティ・オブジェクトの慣用名が「TheCustomer(Customers): 拡張済」のように表示されます。エンティティ・オブジェクトの慣用名の型はカッコ内で示され、「拡張済」というラベルはエンティティ・オブジェクトの慣用名が現在は親から継承されていることを示します。

  3. 「使用可能」リストで、継承されたものをオーバーライドする目的のエンティティ・サブタイプを選択します。既存のエンティティ・オブジェクトの慣用名型のサブタイプ・エンティティである必要があります。

    たとえば、Customersエンティティ型に基づいて継承されたエンティティ・オブジェクトの慣用名をオーバーライドするには、「使用可能」リストでDomesticsエンティティ・オブジェクトを選択します。

  4. 「>」をクリックして、「選択済」リストに移動します。

  5. 表示される警告に応答し、既存の継承されたエンティティ・オブジェクトの慣用名をオーバーライドすることを確認します。

この手順を実行すると、「選択済」リストが更新されて、オーバーライドされたエンティティ・オブジェクトの慣用名を反映するようになります。たとえば、DomesticListビュー・オブジェクトの場合は、Customersベースのエンティティ・オブジェクトの慣用名をDomesticsエンティティ・サブタイプでオーバーライドすると、表示が「TheCustomer (Domestics): オーバーライド済」に更新されます。

エンティティ・オブジェクトの慣用名をエンティティ・サブタイプに関係するようにオーバーライドした後は、エディタの「属性」タブを使用して、そのサブタイプに固有の追加属性を選択できます。たとえば、DomesticsListビュー・オブジェクトには、Domesticsエンティティ・オブジェクトに固有の、Stateという名前の追加属性が含まれます。

7.3.2.2 エンティティ・オブジェクトの慣用名をオーバーライドした後のサブタイプ固有のメソッドへの委譲

拡張されたビュー・オブジェクトのエンティティ・オブジェクトの慣用名をサブタイプ・エンティティを参照するようにオーバーライドした後は、サブタイプ・エンティティ・クラスに固有のメソッドに委譲するビュー行メソッドを作成できます。例7-5は、InternationalListビュー・オブジェクトに対するカスタム・ビュー行クラスのperformInternationalFeature()メソッドのコードを示しています。getTheCustomer()エンティティ行アクセッサからの戻り値をサブタイプInternationalsImplにキャストした後、Internationalsエンティティ・オブジェクトに固有のperformInternationalFeature()メソッドをコールしています。

例7-5 サブタイプ・エンティティのメソッドに委譲するビュー行メソッド

// In InternationalListRowImpl.java
public void performInternationalFeature() {
   InternationalsImpl international = (InternationalsImpl)getTheCustomer();
   international.performInternationalFeature();
}

注意:

JDeveloperでは、InternationalListRowImplのようなサブクラスがgetTheCustomer()のようなメソッドをオーバーライドしてその戻り型を変更できるようにする共変戻り型と呼ばれるJDKの機能がまだ採用されていないため、ここではエンティティ・サブタイプに明示的にキャストする必要があります。


7.3.2.3 クライアント・コードでの異なるビュー行インタフェース型の使用

例7-6は、次の手順を実行するTestViewRowPolymorphismクラスのコード行を示しています。

  1. CustomerListビュー・オブジェクトの行を反復処理します。

    ループでは、各行について、Javaのinstanceof演算子を使用して、現在の行がDomesticListRowまたはInternationalListRowのインスタンスかどうかを検査しています。

  2. 行がDomesticListRowの場合は、行をこのさらに具体的な型にキャストした後、次の処理を行います。

    • DomesticListRowインタフェースに固有のperformDomesticFeature()メソッドをコールします。

    • DomesticListビュー・オブジェクトに固有のState属性の値にアクセスします。

  3. 行がInternationalListRowの場合は、行をこのさらに具体的な型にキャストした後、次の処理を行います。

    • InternationalListRowインタフェースに固有のperformInternationalFeature()メソッドをコールします。

    • InternationalListビュー・オブジェクトに固有のLanguage属性の値にアクセスします。

  4. それ以外の場合は、CustomerListRowでメソッドをコールします。

例7-6 クライアント・コードでのビュー行ポリモフィズムの使用

// In TestViewRowPolymorphism.java
ViewObject vo = am.findViewObject("CustomerList");
vo.executeQuery();
// 1. Iterate over the rows in the CustomerList view object
while (vo.hasNext()) {
  CustomerListRow Customer = (CustomerListRow)vo.next();
  System.out.print(Customer.getEmail()+"->");
  if (Customer instanceof DomesticListRow) {
    // 2. If the row is a DomesticListRow, cast it
    DomesticListRow mgr = (DomesticListRow)Customer;
    mgr.performDomesticFeature();       
    System.out.println("State: "+domestic.getState());
  }
  else if (Customer instanceof InternationalListRow) {
    // 3. If the row is an InternationalListRow, cast it
    InternationalListRow international = (InternationalListRow)Customer;
    international.performInternationalFeature();       
    System.out.println("Speaks English: "+international.getLanguage());        
  }
  else {
    // 4. Otherwise, just call a method on the CustomerListRow 
    Customer.performCustomerFeature();
  }
}

例7-6のコードを実行すると、次のような出力が生成されます。

daustin->## performInternationalFeature called
English spoken: Yes
hbaer->## performCustomerFeature as Customer
:
sking->## performDomesticFeature called
State: CA
:

これは、ビュー行ポリモフィズムの機能を使用することで、クライアントが異なる型のビュー行を区別し、ビュー行の各サブタイプに固有のメソッドと属性にアクセスできたことを示します。