9.13 設計上の考慮点のヒントおよび技法

Oracleのオブジェクト型を使用した作業の様々な側面において多種多様なヒントがあります。

内容は次のとおりです。

9.13.1 型進化かサブタイプの作成かの決定

アプリケーションがライフ・サイクルを終了するまでには、既存のオブジェクト型を変更するか、それとも、新しい要件を満たす特化されたサブタイプを作成するか、という問題が頻繁に発生します。その答えは、新しい要件の性質およびアプリケーションのセマンティクス全体でのコンテキストによって異なります。次に2つの例をあげて説明します。

広範囲に使用されているベース型の変更

属性StreetStateZIPを持つオブジェクト型addressがあるとします。

CREATE TYPE address AS OBJECT (
  Street  VARCHAR2(80),
  State   VARCHAR2(20),
  ZIP     VARCHAR2(10));
/

後になって、世界各地の住所をサポートするためには、Country属性を追加してaddress型を拡張する必要性に気がつきます。addressのサブタイプの作成とaddress型自体の進化とでは、どちらが得策でしょうか。

アプリケーション全体にわたって広範囲に使用されている一般的なベース型の場合は、型進化を通じて変更を実行することをお薦めします。

特化の追加

図形型(たとえば、曲線、円、正方形、テキスト)の既存の型階層に、追加のバリエーション、具体的にはベジエ曲線を格納する必要があるとします。ベース型の不足を反映しないこのような新しい特化をサポートするために、継承を使用して、Curve型の下に、新しいサブタイプBezierCurveを作成する必要があります。

つまり、必要とされる変更のセマンティクスによって、型進化を使用すべきか、それとも継承を使用すべきかが決まります。より全般的な変更で、ベース型に影響が及ぶ場合は、型進化を使用してください。より特化された変更に対しては、継承を使用して変更を実行してください。

9.13.2 ANYDATAとユーザー定義型の相違点

ANYDATAはOracleによって提供される型で、任意のOracleデータ型のインスタンスを、組込み型かユーザー定義かにかかわらず保持できます。ANYDATAは自己記述的な型で、インスタンスの形式を決定するために使用できるリフレクションに類似したAPIです。

代入性機能を通して、継承およびANYDATAは、ともにプレースホルダ内に考えられるインスタンスの任意の集合を格納するポリモフィックな能力を備えていますが、この2つのモデルがその機能を提供する形式は異なります。

継承モデルの場合は、考えられるインスタンスのポリモフィックな集合は、単一の型の階層の一構成部分である必要があります。変数には、定義された型またはそのサブタイプのインスタンスのみを保持する潜在的な能力があります。スーパータイプの属性にアクセスして、そのサブタイプで定義されている(またサブタイプによってオーバーライドされる可能性のある)メソッドをコールできます。IS OF演算子およびTREAT演算子を使用して、あるインスタンスの具体的な型をテストすることもできます。

ただし、ANYDATA変数は、異質なインスタンスを格納する可能性があります。インスタンスを抽出してしまわないかぎり、ANYDATA変数に格納されている実際のインスタンスの属性にアクセスすることも、メソッドをコールすることもできません。該当するインスタンスの型を抽出するには、ANYDATAメソッドを使用します。ANYDATAは、ファンクション/プロシージャがパラメータの具体的な型には関心がない場合にパラメータの受渡しを行う場合に便利です。

継承は優れたモデリング、厳密な型指定、特化などを提供します。共通するものがあるとはかぎらない、任意の数の考えられるインスタンスのうちの1つを保持するのみの場合は、ANYDATAを使用してください。

9.13.3 ポリモフィック・ビュー: オブジェクト・ビュー階層の代入

「オブジェクト・モデルのリレーショナル・データへの適用」では、それぞれが単一の型のオブジェクトを含んでいるオブジェクト・ビューの集合からビュー階層を構築する方法について説明しています。このようなビュー階層では、その階層内のビューに対する問合せによる、ビューまたはそのサブビューによって格納されたオブジェクトのポリモフィックな集合の参照が可能です。

このようなポリモフィックな問合せをサポートする代入の方法として、オブジェクトのポリモフィックな集合を戻す問合せに基づいてオブジェクト・ビューを定義できます。このアプローチは、あるビューを既存の表またはビューの集合にまたがって定義するときに特に便利です。

たとえば、Person_tのオブジェクト・ビューを、Employee_tインスタンスも含めたPerson_tインスタンスを戻す問合せに対して定義できます。次の文からは、persons表から個人を、employees表から従業員を選択する問合せに基づいてビューが作成されます。

CREATE VIEW Persons_view OF Person_t AS
SELECT Person_t(...) FROM persons
UNION ALL
SELECT TREAT(Employee_t(...) AS Person_t) FROM employees;

このビューに対して定義されているINSTEAD OFトリガーのかわりに、VALUEファンクションを使用して、現在のオブジェクトにアクセスでき、また、オブジェクトの最も具体的な型に基づいて適切なアクションをとることができます。

ポリモフィック・ビューとオブジェクト・ビュー階層には、次のような重要な相違点があります。

  • アドレス指定可能度: ビュー階層では、各サブビューは、問合せおよびDML文の中で別々に参照できます。したがって、特定の型のオブジェクトの各集合には、論理名があります。一方、ポリモフィック・ビューは単一のビューなので、特定の型のオブジェクトの集合を取得するには、述語を使用する必要があります。

  • 進化: 新しいサブタイプを追加する場合は、既存のビュー定義を変更することなくビュー階層にサブビューを追加できます。ポリモフィック・ビューの場合は、別のUNIONブランチを追加することによって、単一のビュー定義を変更する必要があります。

  • DML文: ビュー階層では、各サブビューは、本質的に更新可能であるか、INSTEAD OFトリガーを持っているかのいずれかです。ポリモフィック・ビューの場合は、ビュー上の与えられた操作に対してINSTEAD OFトリガーを1つのみ定義できます。

9.13.4 SQLJオブジェクト型

この項では、SQLJオブジェクト型について説明します。

内容は次のとおりです。

9.13.4.1 SQLJオブジェクト型の使用目的

『Information Technology - SQLJ - Part 2』ドキュメント(SQLJ規格)によると、SQLJオブジェクト型は、Java用に設計されたデータベース・オブジェクト型です。SQLJオブジェクト型はJavaクラスにマップされます。マッピングが拡張SQLのCREATE TYPEコマンド(DDL文)によって登録されると、JavaアプリケーションでOracle JDBCドライバを通じて、Javaオブジェクトを直接またはデータベースから、挿入または選択できるようになります。したがって、ユーザーは、同じクラスを、クライアントではJDBCを使用して、サーバーではSQLメソッドのディスパッチによって、デプロイできます。

9.13.4.2 SQLJオブジェクト型作成時に実行されるアクション

拡張SQLのCREATE TYPEコマンドは、次のことを行います。

  • データベース・カタログに属性、ファンクションおよびJavaクラスの外部名を移入します。また、Javaクラスとそれに対応するSQLJオブジェクト型間の依存関係は維持されます。

  • Javaクラスが存在することを検証し、また、それによってUSING句の値に対応するインタフェースが実装されることも検証します。

  • Javaフィールドが(EXTERNAL NAME句で指定されているとおりに)存在すること、また、これらのフィールドが対応するSQL属性に対する互換性を検証します。

  • コンストラクタ、外部変数名、結果としてselfを返す外部ファンクションをサポートする内部クラスを生成します。

9.13.4.3 SQLJオブジェクト型の用途

SQLJオブジェクト型は、SQLオブジェクト型の特殊なケースで、すべてのメソッドがJavaクラスで実装されています。

Javaクラスと対応するSQL型間のマッピングは、SQLJオブジェクト型仕様によって管理されます。つまり、SQLJオブジェクト型仕様には、対応する型本体の仕様はありません。

また、SQLJオブジェクト型間の継承ルールによって、Javaクラス階層と対応するSQLJオブジェクト型階層の正しいマッピングが指定されます。これらのルールによって、SQLJ型階層に有効なマッピングが含まれていることが保証されます。したがって、SQLJオブジェクト型のスーパータイプまたはサブタイプは別のSQLJオブジェクト型である必要があります。

9.13.4.4 カスタム・オブジェクト型の用途

カスタム・オブジェクト型は、SQLオブジェクト型にアクセスするためのJavaインタフェースです。SQLオブジェクト型には、PL/SQL、Java、Cなどの言語で実装されたメソッドが含まれている場合があります。与えられたSQLオブジェクト型内のJavaで実装されたメソッドは、関連のない様々なクラスに属することができます。つまり、SQLオブジェクト型は特定のJavaクラスにマップされるわけではありません。

クライアントがこれらのオブジェクトにアクセスできるようにするため、JPublisherを使用して対応するJavaクラスを生成できます。さらに、ユーザーは、生成されたクラスを、対応するメソッドのコードで補強する必要があります。別の方法として、SQLオブジェクト型に対応するクラスを作成する方法もあります。

JDBCユーザーは、マップ内のSQL型名とそれに対応するJavaクラス間の対応関係を実行時に登録する必要があります。

9.13.4.5 SQLJオブジェクト型とJDBCを使用したカスタム・オブジェクト型の相違点

次の表は、SQLJオブジェクト型とカスタム・オブジェクト型の相違点の要約です。

表9-1 SQLJオブジェクト型とカスタム・オブジェクト型の相違点

特性 SQLJオブジェクト型の動作 カスタム・オブジェクト型の動作

型コード

OracleTypes.JAVA_STRUCT型コードを使用して、SQLJオブジェクト型をSQLのOUTパラメータとして登録します。OracleTypes.JAVA_STRUCT型コードは、ORADataインタフェースまたはSQLDataインタフェースを実装しているクラスの_SQL_TYPECODEフィールドでも使用されます。

OracleTypes.STRUCT型コードを使用して、カスタム・オブジェクト型をSQLのOUTパラメータとして登録します。OracleTypes.STRUCT型コードは、ORADataインタフェースまたはSQLDataインタフェースを実装しているクラスの_SQL_TYPECODEフィールドでも使用されます。

作成

まず、SQLDataまたはORADataインタフェースおよびORADataFactoryインタフェースを実装するJavaクラスを作成してから、Javaクラスをデータベースにロードします。次に、SQLJオブジェクト型に対して拡張SQLのCREATE TYPEコマンドを発行します。

カスタム・オブジェクト型に対して拡張SQLのCREATE TYPEコマンドを発行してから、JPublisherを使用して、または手動でSQLDataまたはORADataのJavaラッパー・クラスを作成します。

メソッド・サポート

外部名、コンストラクタ・コール、副作用のあるメンバー・ファンクションへのコールをサポートします。

型メソッドをJavaメソッドとして実装するデフォルト・クラスはありません。一部のメソッドはSQLでも実装できます。

型マッピング

型マッピングは、拡張SQLのCREATE TYPEコマンドによって自動的に行われます。ただし、SQLJオブジェクト型には、それを定義するJavaクラスがクライアント上にある必要があります。

型マップでのSQLとJavaの対応関係を登録します。対応関係にない場合、その型はoracle.sql.STRUCTとして実現されます。

継承

SQL階層をJavaクラス階層にマップするためのルールがあります。これらのルールの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

マッピング・ルールはありません。

9.13.5 その他の設計ヒント

Oracleオブジェクトの設計に関するその他のヒントを認識しておく必要があります。

9.13.5.1 階層内の列の置換え可能性と属性の数

列または表が型Tである場合は型Tの各属性に対して、列または表が代入可能な場合はTの各サブタイプの各属性に対して、属性データを格納するために非表示列が追加されます。同様に、行の中のオブジェクト・インスタンスの型を追跡するため、非表示のtypeid列も追加されます。

1つの表内の列の数は、1,000に制限されています。属性の合計数が1,000に迫っている型階層では、その階層内の型の置換え可能な列を使用しているときにこの制限を超えてしまうというリスクがあります。この結果発生する問題を回避するため、属性の合計数が大きい階層については、次のオプションのいずれかを検討してください。

  • ビューの使用

  • REFの使用

  • 階層の分割

9.13.5.2 型間の循環的依存関係

型間に循環的な依存関係を発生させることは避けてください。つまり、T型のメソッドが、型T1 (T型を戻すメソッドを持つ)を戻すような状況を発生させないでください。