6 マッピングの理解
EclipseLinkでは、オブジェクト表現とデータ・ソース固有の表現との間でデータのトランスフォーメーションを実行できます。
このトランスフォーメーションをマッピングと呼びますが、マッピングは、EclipseLinkプロジェクトの中核をなしています。
マッピングはそれぞれ、ドメイン・オブジェクトの単一データ・メンバーに対応しています。マッピングによって、オブジェクト・データ・メンバーをそのデータ・ソース表現と関連付け、オブジェクトとデータ・ソースの間の双方向変換を実行する手段を定義します。
共通のマッピングの概念
この項では、EclipseLinkに固有のリレーショナル・マッピングと非リレーショナル・マッピングの概念について説明します。
マッピング・アーキテクチャ
マッピングを定義するには、次のコンポーネントを利用します。
-
オブジェクトのデータを格納するデータ・ソース(リレーショナル・データベース表またはスキーマ定義のXML要素など)に固有のデータ表現
-
特定オブジェクト・クラスのディスクリプタ
-
マップするオブジェクト・クラス
注意:
マッピングは、プロジェクトの永続性の有無にかかわりなく同じです。
標準的なEclipseLinkマッピングの例については、「マッピングの例」を参照してください。
プロジェクトで定義するデータ・ソースのタイプによって、使用できるマッピングのタイプおよびその構成方法が決まります。永続プロジェクトでは、マッピングを使用してデータ・ソースを永続させます。永続ではないプロジェクトでは、オブジェクト形式とその他の一部のデータ表現(XMLなど)の間で単に変換を行うためにマッピングを使用します。
ディスクリプタは、特定のドメイン・オブジェクトを表し、オブジェクトのクラスを記述します。ディスクリプタは、マッピングも所有します(メモリー内で永続化または変換するクラス・データ・メンバーごとに1つのマッピング)。ディスクリプタの詳細は、「ディスクリプタの理解」を参照してください。
マッピングの例
EclipseLinkでは、より複雑なマッピングをサポートしますが、ほとんどのEclipseLinkのクラスは、クラスで使用可能な情報のタイプを定義する1つのデータベース表またはXML要素にマップされます。
特定のクラスからインスタンス化された各オブジェクトは、一意にオブジェクトを識別する識別子(主キー)を付加して、オブジェクトの属性を構成する1つの行にマップされます。
次の図は、最も単純なデータベース・マッピングの例を示します。
-
データベースのTable_Xは、Class_Xを表します。
-
Object_X1およびObject_X2は、Class_Xのインスタンスです。
-
Table_Xの各行は、Object_X1およびObject_X2に加えて、Class_Xのその他のインスタンスも表します。
EclipseLinkには、上の図に示した単純なマッピングから複雑なマッピングまでのマッピングを作成するためのツールが用意されています。
リレーショナル・マッピングのその他の例は、「マッピング・コンバータ」を参照してください。
マッピング・コンバータ
既存のEclipseLinkマッピングがニーズを満たしていない場合、マッピングの拡張機能を使用してカスタムのマッピングを作成できます。
注意:
シンプル・タイプ変換以外では、データ・ソースがリレーショナルかリレーショナルでないかにかかわらず、マッピング・コンバータおよびトランスフォーマを使用できます。シンプル・タイプ変換は、XMLプロジェクトにのみ適用されます。
シリアライズ・オブジェクト・コンバータ
シリアライズ・オブジェクト・コンバータは、Javaオブジェクト・シリアライズを介して複雑なオブジェクトをバイナリ・フィールドにマップできるダイレクト・マッピングおよびダイレクト・コレクション・マッピングで使用できます。シリアライズされたオブジェクトは、通常、データベースのRAW
またはバイナリ・ラージ・オブジェクト(BLOB)フィールド、またはXML文書のHEX
またはBASE64
要素に格納されます。
次の図は、シリアライズ・オブジェクト・コンバータを使用したフィールドへ直接マッピングの例を示しています。属性jobDescription
には、データベースのJOB_DESC
フィールドに格納される、書式設定されたテキスト文書が含まれています。
図6-3に、シリアライズ・オブジェクト・コンバータを使用する非リレーショナル・マッピングの例を示します。属性jobDescriptionには、EclipseLinkによってXMLスキーマのJOB DESCRIPTION
要素に格納される、書式設定されたテキスト文書が含まれています。
シリアライズ・オブジェクト・コンバータは、Javaシリアライザを利用します。ドメイン・オブジェクトをシリアライズ・オブジェクト・コンバータでマップする前に、ドメイン・オブジェクトにjava.io.Serializable
インタフェースが実装され(または実装が継承され)、シリアライズされていないすべてのフィールドにtransientがマークされていることを確認してください。
タイプ変換コンバータ
タイプ変換コンバータは、複雑なオブジェクトをバイナリ・フィールドにマップできるダイレクト・マッピングおよびダイレクト・コレクション・マッピングで使用できます。たとえば、データ・ソースのNumberをJavaのString
にマップすることや、Javaのjava.util.Date
をデータ・ソースのjava.sql.Date
にマップすることができます。
java.util.Date
クラスは、デフォルトではTimestamp
としてデータベースに格納されるため、そのクラスは、まず、java.sql.Date
のような明示的なデータベース・タイプに変換する必要があります(これはDB2に対してのみ必須であり、その他の大部分のデータベースには、任意の日付または時間を格納できる単一日付のデータ・タイプがあります)。
次の図は、タイプ変換マッピング(非リレーショナル)を示しています。java.util.DateオブジェクトがXMLスキーマのString
にマップされています。
データベース用に特別にタイプ処理が必要な場合、タイプ変換コンバータを使用してその特定のデータベースを指定できます。コンバータには、5Kを超えるBLOB
およびCLOB
フィールドの処理に必要なOracle Thin JDBCの特別な挿入および更新と同様に、NCHAR
、NVARCHAR2
およびNCLOB
フィールドに必要な特別なOracle JDBCの特別なバインド・オプションのためのサポートが含まれています。
EclipseLinkは、org.eclipse.persistence.platform.database.oracleパッケージのNCharacter、NClobおよびNStringタイプをコンバータのデータ・タイプとして使用し、NCHAR、NCLOBおよびNVARCHAR2タイプをサポートしています。EclipseLinkは、java.sql.BlobおよびClobタイプをコンバータのデータ・タイプとして使用して、5Kを超えるBLOBおよびCLOBの値をサポートしています。
データ・ソースの時間型(TIMESTAMP
など)をjava.lang.Stringにマップするためにタイプ変換コンバータを構成できます。ただし、String値が次の書式に一致していることが条件です。
-
YYYY/MM/DD HH:MM:SS
-
YY/MM/DD HH:MM:SS
-
YYYY-MM-DD HH:MM:SS
-
YY-MM-DD HH:MM:SS
より複雑なStringをTIMESTAMP型に変換する場合は、トランスフォーメーション・マッピングを検討してください(「トランスフォーメーション・マッピング」を参照)。
@TypeConverter注釈を使用して、マップ済属性の読取りおよび書込み中にデータ値を変更することもできます。各TypeConverterは、一意の名前を付ける必要があり、クラス、フィールドおよびプロパティ・レベルで定義でき、Entity、MappedSuperclassおよびEmbeddableクラス内で指定できます。TypeConverterは、常に@Convert注釈を使用して指定されます。
@TypeConverterをBasic、BasicMapまたはBasicCollectionマッピングに配置できます。これらの注釈の詳細は、『Java Persistence API (JPA) Extensions Reference for EclipseLink』を参照してください。
オブジェクト・タイプ・コンバータ
オブジェクト・タイプ・コンバータは、一定数の値をJavaオブジェクトに対応させることができるダイレクト・マッピングおよびダイレクト・コレクション・マッピングで使用できます。このコンバータは、スキーマにある値がJavaにある値と異なる場合に使用します。
次の図は、Employee属性のgenderとXML要素のgenderとの間のオブジェクト・タイプの変換を示しています。Javaのオブジェクト属性の値がFemaleの場合、EclipseLinkではその値がFとしてXML要素に格納されます。
@ObjectTypeConverter注釈を使用した、オブジェクト・タイプの変換の実行もできます。この注釈は、マップ済属性の読取りおよび書込み中にデータベース・データ値の固定数をJavaオブジェクト値に変換するorg.eclipse.persistence.mappings.converters.ObjectTypeConverterを指定します。この注釈には、@ConversionValue注釈を使用して、変換値の配列に対する値を提供する必要があります。詳細は、『Java Persistence API (JPA) Extensions Reference for EclipseLink』の@ObjectTypeConverterおよび@ConversionValueinの説明を参照してください。
トランスフォーメーション・マッピング
ある種の特殊な状況においては、データ・ソースの処理に関して、既存のマッピング・タイプおよびそのデフォルトのJavaでは、不十分な場合が考えられます。
注意:
トランスフォーメーション・マッピングは複雑なため、多くの場合、コンバータまたはフィールドへ直接マッピングのgetterおよびsetterメソッドを使用する方が簡単に変換を実行できます。
次の図に、トランスフォーメーション・マッピングを示します。B_DATEおよびB_TIMEフィールドからの値は、birthDate属性に格納されるjava.util.Dateの作成に使用されます。
トランスフォーメーション・マッピングは、次の2つのコンポーネントで構成されています。
-
属性トランスフォーマ: 読取り時にオブジェクト属性トランスフォーメーションを実行します。
-
フィールド・トランスフォーマ: 書込み時にオブジェクト属性からフィールドへのトランスフォーメーションを実行します。
トランスフォーマは、別個のクラスまたはドメイン・オブジェクトでのメソッドのいずれかとして実装できます。
多くの場合、トランスフォーメーション・マッピングは、複数のフィールドの値を使用して1つのオブジェクトを作成する場合に適しています。このタイプのマッピングでは、データベースからオブジェクトを読み取る際に起動される、属性トランスフォーメーションが必要です。これには、Recordのインスタンスであるパラメータを1つ以上持たせる必要があります。属性トランスフォーメーションでは、特定の列の値の取得にRecordメソッドgetを使用できます。属性トランスフォーメーションは、オプションで2番目のパラメータ(Sessionのインスタンス)を指定できます。Sessionは、トランスフォーメーションで必要な追加の値を取得するために、データベースで問合せを実行します。トランスフォーメーションにより、属性に格納される値が返されます。
トランスフォーメーション・マッピングでは、オブジェクトが保存される際にデータベースに書き込まれる、各フィールドに対するフィールド・トランスフォーメーションも必要です。トランスフォーメーションは、そのフィールドに格納される値を返します。
属性およびフィールド・トランスフォーメーションの実装時には、アプリケーション・データをデータ・ソースに、またはその逆に適合させるための変換に必要な、どのような処置も講じることができます。
@Transformation属性を使用して、データベース列値と属性値のトランスフォーメーション・マッピングを実行できます。@WriteTransformerおよび@ReadTransformer注釈とともにこの注釈を使用します。@WriteTransformer注釈は、単一の属性値を単一のデータベース列値に変換するために使用します。この注釈については、FieldTransformerインタフェースの実装を提供することもできます。@ReadTransformer注釈については、org.eclipse.persistence.mappings.transformers.AttributeTransformerインタフェースの実装を提供する必要があります。これらの注釈の詳細は、『Java Persistence API (JPA) Extensions Reference for EclipseLink』の@Transformation、@ReadTransformerおよび@WriteTransformerの説明を参照してください。
オブジェクト・リレーショナル・マッピングの概念
この項では、EclipseLinkに固有のリレーショナル・マッピングの概念について説明します。
インダイレクション(遅延ロード)
デフォルトでは、EclipseLinkは永続オブジェクトを取得する際に、そのオブジェクトが参照する依存オブジェクトをすべて取得します。
リレーションシップ・マッピングによってマップされた属性に対してインダイレクション(遅延読取り、遅延ロードおよびジャストインタイム読取りとも呼びます)を構成すると、参照オブジェクトのプレースホルダとしてインダイレクション・オブジェクトが使用されます(EclipseLinkは、その特定の属性がアクセスされるまで、依存オブジェクトの読取りを遅延します)。その結果、アプリケーションにとって重要なのは取得されたオブジェクトの内容のみであり、関連オブジェクトの内容は重要でないという場合は特に、パフォーマンスが大幅に向上します。
注意:
-
インダイレクションの使用は、双方向リレーションシップの適切なメンテナンスのために特に重要です。この場合、インダイレクションを使用する必要があります。コレクションを操作する場合は、透過インダイレクションを使用する必要があります(「透過インダイレクション」を参照)。
-
インダイレクション(遅延ロード)の実装はベンダー固有です。LAZY属性またはフィールドやリレーションシップが使用されている場合、エンティティのシリアライズおよび永続性コンテキストへのマージが、ベンダー間で相互運用できない場合があります。
次の図に、インダイレクションの例を示します。インダイレクションを使用しない場合、Orderオブジェクトを読み取ると、依存コレクションであるLineItemオブジェクトも読み取られます。インダイレクションを使用する場合、Orderオブジェクトを読み取っても、LineItemオブジェクトの依存コレクションは読み取られません(lineItems属性は、インダイレクション・オブジェクトを参照します)。customerIdなどの他の属性にアクセスできますが、EclipseLinkが依存LineItemオブジェクトを読み取るのは、lineItems属性にアクセスした場合のみです。
EclipseLinkでは、次のインダイレクション・タイプをサポートします。
アプリケーションのシリアライズ対象となるオブジェクトにインダイレクションを使用する場合、デシリアライズ時にトリガーされないインダイレクション・オブジェクトの影響を検討する必要があります。「インダイレクション、シリアライズおよびデタッチ」を参照してください。
インダイレクション、シリアライズおよびデタッチ
インダイレクション(遅延ロード)を使用している場合、永続オブジェクトのグラフにトリガーされていないインダイレクション・オブジェクトが含まれる可能性があります
インダイレクション・オブジェクトは一時オブジェクトで、1つのJVMと別のJVMの間でシリアライズが存続することはないため、トリガーされていないインダイレクション・オブジェクトでは、デシリアライズ後にリレーションシップへのアクセスが行われるとエラーがトリガーされます。
アプリケーションでは、デシリアライズ後に必要なインダイレクト・リレーションシップがシリアライズ前にインスタンス化されていることを確認する必要があります。これを行うには、ValueHolder
またはウィービング済インダイレクションを使用して任意のリレーションシップのgetメソッドにアクセスし、透過インダイレクションを使用して任意のリレーションシップのsizeメソッドをコールします。アプリケーションで、シリアライズ時にリレーションシップを常にインスタンス化する場合、永続クラスのシリアライズwriteObjectメソッドを上書きして、最初に目的のリレーションシップをインスタンス化できます。多数のリレーションシップや階層の深いリレーションシップを持つオブジェクトでは、ラージ・オブジェクト・グラフをシリアライズしないように注意してください(クライアントで必要とされるリレーションシップのみがインスタンス化されるのが理想的です)。
JPAエンティティをシリアライズする場合、シリアライズの前にインスタンス化されていないLAZYリレーションシップは、アクセスされるとエラーの原因となります。ウィービングをサーバーで使用し、エンティティをクライアントにシリアライズする場合、jarの静的ウィービングを通じて、またはEclipseLinkエージェントを使用したクライアントJVMの起動を通じて、同じウィービング・クラスがクライアントに存在している必要があります。
詳細は、「実装オプション」を参照してください。
ValueHolderインダイレクション
インダイレクションを使用する永続クラスは、リレーションシップ属性を値ホルダー属性に置き換える必要があります。
ValueHolderは、ValueHolderなど、ValueHolderInterfaceインタフェースを実装するクラスのインスタンスです。このオブジェクトには、置き換えられるオブジェクトをデータベースから取得するために必要な情報が格納されます。アプリケーションがValueHolderにアクセスしないと、置き換えられたオブジェクトはデータベースから読み取られません。
ValueHolderが置き換えるオブジェクトを取得するには、ValueHolderInterfaceのgetValueおよびsetValueメソッドを使用します。これらのメソッドを使用する便利な方法としては、次の例で示すように、ValueHolderInterfaceのgetValueおよびsetValueメソッドを、getおよびsetメソッド内で非表示にする方法があります。
次の図に、データベースから読み取られるEmployeeオブジェクトを示します。Addressオブジェクトは読み取られず、アクセスするまで作成されません。
次の図に示すとおり、最初のアドレスへのアクセス時に、ValueHolderはAddressオブジェクトを読み取り、それを返します。
次の図に示すように、アドレスに対する後続のリクエストではデータベースにアクセスしません。
メソッド・アクセスを使用している場合、マッピングで指定されたgetおよびsetメソッドは、ValueHolderが参照しているオブジェクトではなく、ValueHolderInterfaceのインスタンスにアクセスする必要があります。アプリケーションがこれらのgetterおよびsetterを使用することはありませんが、ValueHolderの使用を隠すgetterおよびsetterを使用します。
透過インダイレクション
EclipseLinkでは、適切なインタフェースを実装し、関連オブジェクトのJust-in-Time方式による読取りも実行するインダイレクション・オブジェクトが使用されます。
透過インダイレクションでは、次のいずれかのJavaオブジェクトとして関連オブジェクトのコレクションを保持する永続クラスの任意のリレーションシップ属性を宣言します。
-
java.util.Collection
-
java.util.Hastable
-
java.util.List
-
java.util.Map
-
java.util.Set
-
java.util.Vector
透過インダイレクションを使用する場合、属性をValueHolderInterfaceとして宣言する必要はありません。
新たに作成されたコレクション・マッピングは、属性がValueHolderInterfaceではない場合、デフォルトで透過的なインダイレクションを使用します。
JPAエンティティおよびPlain Old Java Object (POJO)クラスに対しては、透過インダイレクト・コンテナ・インダイレクションのウィービングが自動的に実行されるようEclipseLinkを構成できます。詳細は、「実装オプション」および「ウィービングについて」を参照してください
プロキシ・インダイレクション
JavaクラスのProxyを使用して、定義済インタフェースのプレースホルダとして動的プロキシ・オブジェクトを使用できます。
特定のEclipseLinkマッピングを構成してプロキシ・インダイレクションを使用し、EclipseLinkクラスをドメイン・モデルに含めることなく、インダイレクションの利点を得ることができます。プロキシ・インダイレクションは1対1リレーションシップ・マッピングに対応し、インダイレクション・コンテナはコレクション・マッピングに対応します。
プロキシ・インダイレクションを使用するには、ドメイン・モデルが次の条件をすべて満たしている必要があります。
-
1対1リレーションシップのターゲット・クラスがパブリック・インタフェースを実装していること
-
ソース・クラスの1対1属性が、interfaceタイプである必要があります。
-
メソッド・アクセスを使用する場合、getterメソッドおよびsetterメソッドはインタフェースを使用する必要があります。
プロキシ・インダイレクションを使用する前に、永続性ユニットの使用方法に設定されている制限に注意してください(「プロキシ・インダイレクションの制限」を参照)。
プロキシ・インダイレクションを構成するため、修正メソッドでJDeveloperまたはJavaを使用できます。
プロキシ・インダイレクションの制限
Javaのプロキシ・オブジェクトは、送信されるメッセージの遮断にのみ使用できます。==、instanceofまたはgetClassなどのプリミティブ操作がプロキシで使用されている場合は、メッセージは遮断されません。プロキシ・オブジェクトの使用に関しては、アプリケーションでこの制限に多少注意することが必要です。
プロキシ・インダイレクションの実装のターゲットは永続性ユニットに登録できません。かわりに、先にソース・オブジェクトを永続性ユニットに登録します。これにより、ソース・オブジェクト・クローンでgetterコールを使用し、ターゲット・オブジェクト・クローンを取得できます。
ウィービング済インダイレクション
ウィービング用に構成したJPAエンティティまたはPOJOクラスの場合、EclipseLinkでは、1対1マッピングのValueHolderインダイレクションのウィービングが実行されます。
アプリケーションにコレクション・マッピング(1対多または多対多)が含まれている場合にEclipseLinkで変更追跡に対するウィービングが実行されるようにするには、すべてのコレクション・マッピングに対し、透過インダイレクト・コンテナ・インダイレクションのみが使用されるように構成する必要があります(コレクション・マッピングは、即時ロードやValueHolderインダイレクションが使用されるようには構成できません)。
詳細は、「実装オプション」を参照してください。
JPAマッピング・タイプについて
リレーショナル表にエンティティ・クラスをマップするには、永続フィールドごとにマッピングを構成する必要があります。
次の項では、EclipeLinkのJPAマッピング・タイプについて説明します。
-
基本マッピング
-
デフォルトの変換およびコンバータ
-
コレクション・マッピング
-
オプティミスティック・ロックの使用
基本マッピング
シンプルJavaタイプは、エンティティの即時状態の一部としてそのフィールドまたはプロパティにマップされます。シンプルJavaタイプのマッピングは、基本マッピングと呼ばれます。
デフォルトでは、EclipseLink永続性プロバイダによって、シンプル・タイプの基本マッピングが自動的に構成されます。
次の注釈を使用して、アプリケーションでこれらのマッピングを実装する方法を調整します。
-
@Basic
-
@Enumerated
-
@Temporal
-
@Lob
-
@Transient
-
@Column
-
遅延の基本(次の「コレクションを使用したインダイレクションの使用」を参照してください。)
すべてのマッピング・タイプに、オプションの共通セットがあります。
-
読取り専用: 読取りおよびコピー時にマッピングで値の移入を行うように指定します。複数のマッピングで同じデータベース列を共有する場合には必須です。
-
コンバータ: ほとんどのマッピング・タイプでカスタム・データ・タイプおよびデータの変換を使用できます。
-
注釈: @Converter、@TypeConverter、@ObjectTypeConverter、@StructConverter、@Convert
-
外部メタデータ: <converter>、<type-converter>、<object-type-converter>、<struct-converter>、<convert>
-
これらの注釈の詳細は、『Java Persistence API (JPA) Extensions Reference for EclipseLink』を参照してください。
デフォルトの変換およびコンバータ
『Java Persistence API (JPA) Extensions Reference for EclipseLink』の「Converter Annotations」には、EclipseLinkが定義するコンバータ注釈の拡張のリストおよび説明へのリンクが記載されています。
次の説明については、『Java Persistence API (JPA) Extensions Reference for EclipseLink』の個々のコンバータ注釈を参照してください。
-
EclipseLink永続性プロバイダがコンバータ注釈を検索する順序
-
コンバータを指定するクラスのタイプ(クラス、フィールドおよびプロパティ・レベルでコンバータを定義できます)
-
コンバータを使用できるマッピング
コレクション・マッピング
DescriptorCustomizerクラスを使用して、EclipseLinkディスクリプタおよびマッピングAPIを通じて追加の拡張マッピングおよびマッピング・オプションにアクセスできます。
1対多マッピングは、1つのソース・オブジェクトとターゲット・オブジェクトのコレクションの間の関連を表すために使用されます。それらは、ターゲット・オブジェクトのCollection(または他のコレクション・タイプ)によるJavaでの実装は簡単だが、リレーショナル・データベースによる実装は難しいもののよい例です。
JavaのCollectionでは、所有者がその一部を参照します。リレーショナル・データベースでは、その一部がその所有者を参照します。リレーショナル・データベースでは、この実装を使用して問合せをより効率的にします。
注意:
1対多リレーションシップに示されているphone属性のタイプは、Vectorです。コレクション属性の宣言にはCollectionインタフェース(またはCollectionインタフェースを実装する任意のクラス)を使用できます。
デフォルトで、JPAでは、1対多の多重度を持つ多値のアソシエーションに対してOneToManyマッピングを自動的に定義します。
@OneToMany注釈を使用して次の操作を行います。
-
フェッチ・タイプをEAGERに構成します。
-
関連するターゲット・エンティティを構成します(使用されるコレクションは汎用を使用して定義されないため)
-
アソシエーションのターゲットにカスケードする必要のある操作を構成します(たとえば、所有側エンティティが削除されると、アソシエーションのターゲットも削除されます)。
-
単方向の1対多リレーションシップのために永続性プロバイダによって使用される結合表の詳細を構成します。mappedByまたはJoinColumnを使用する1対多では、関連オブジェクトの削除がデータベース上でカスケードされます。JoinTableを使用する1対多では、結合表の削除がデータベース上でカスケードされます(ターゲット・オブジェクトは、制約方向のためにプライベートであってもカスケードされません)。
詳細は、JPA仕様の11.1.23項「JoinTable Annotation」を参照してください。
http://jcp.org/en/jsr/detail?id=338
多対多マッピングは、ソース・オブジェクトのコレクションとターゲット・オブジェクトのコレクションの間のリレーションシップを表します。この場合、ソースとターゲットのレコード間の関連を管理するための中間表の作成が必要です。
次の図は、Javaの多対多マッピングおよびリレーショナル・データベース表の多対多マッピングを示しています。
注意:
多対多リレーションシップに示されているプロジェクト属性では、コレクション属性を宣言するためにCollectionインタフェース(またはCollectionインタフェースを実装する任意のクラス)を使用できます。
デフォルトで、JPAでは、多対多の多重度を持つ多値のアソシエーションに対して多対多マッピングを自動的に定義します。
@ManyToMany注釈を使用して次の操作を行います。
-
FetchTypeをEAGERに構成します。
-
NULL値がアプリケーションにとって不適切である場合、NULL値を禁止するようにマッピングを構成します(非プリミティブ・タイプの場合)。
-
関連するターゲット・エンティティを構成します(使用されるコレクションは汎用を使用して定義されないため)
-
アソシエーションのターゲットにカスケードする必要のある操作を構成します(たとえば、所有側エンティティが削除されると、アソシエーションのターゲットも削除されます)。
@ManyToMany注釈でサポートされる属性のリストは、Java Persistence仕様を参照してください。
http://jcp.org/en/jsr/detail?id=338
JPAでは、遅延ロードを、データが最初にアクセスされたときに可能であれば遅延してフェッチするという永続性プロバイダに対するヒントとして規定しています。Java EE環境でアプリケーションを開発する場合、fetchをjavax.persistence.FetchType.LAZYに設定し、必要なすべての機能を永続性プロバイダで提供します。
Java SE環境で1対1または多対1のマッピングを使用する場合、fetch属性をFetchType.LAZYに設定することで、動的ウィービングまたは静的ウィービングを使用して遅延ロードを実行します。また、Java SE環境では、1対多リレーションシップおよび多対多リレーションシップはデフォルトではLAZYで、透過インダイレクションが使用されます。一方、1対1リレーションシップおよび多対1リレーションシップはLAZYではありません。
Java SE環境や、JVMコマンド行で-javaagentの使用が許可されない環境で1対1または多対1のマッピングを使用する場合、fetch属性をFetchType.LAZYに設定することで、静的ウィービングを使用して遅延ロードを実行します。
1対1リレーションシップおよび多対1リレーションシップをLAZYに設定してウィービングを有効にすると、EclipseLink JPA永続性プロバイダでは、ウィービングを介して、これらのリレーションシップに対するValueHolderインダイレクションが有効になります。
コレクション注釈@OneToOne、@OneToMany、@ManyToManyおよび@ManyToOneには、lazyまたはeagerに設定できるfetchマッピング属性が用意されています。属性をlazyに設定すると、EclipseLink JPA永続性プロバイダでインダイレクションが使用されます。
表6-1 マッピング・タイプ別の遅延ロードのサポート
マッピング | Java EE | Java SE |
---|---|---|
多対多 |
fetch属性がjavax.persistence.FetchType.LAZY(デフォルト)に設定されている場合に遅延ロードが実行されます。 |
fetch属性がjavax.persistence.FetchType.LAZY(デフォルト)に設定されている場合に遅延ロードが実行されます。 |
1対多 |
fetch属性がjavax.persistence.FetchType.LAZYに設定されている場合に遅延ロードが実行されます(デフォルト)。 |
fetch属性がjavax.persistence.FetchType.Lazy(デフォルト)に設定されている場合に遅延ロードが実行されます。 |
1対1 |
fetch属性がjavax.persistence.FetchType.LAZYに設定されている場合に遅延ロードが実行されます。 |
fetch属性は無視され、デフォルトのjavax.persistence.FetchType.EAGERが適用されます。 |
多対1 |
fetch属性がjavax.persistence.FetchType.LAZYに設定されている場合に遅延ロードが実行されます。 |
fetch属性は無視され、デフォルトのjavax.persistence.FetchType.EAGERが適用されます |
基本 |
fetch属性がjavax.persistence.FetchType.LAZYに設定されている場合に遅延ロードが実行されます。 |
fetch属性は無視され、デフォルトのjavax.persistence.FetchType.EAGERが適用されます。 |
オプティミスティック・ロックの使用
オプティミスティック・ロックの使用をお薦めします。オプティミスティック・ロックを使用した場合、すべてのユーザーにデータへの読取りアクセス権限があります。ユーザーが変更を書き込もうとすると、アプリケーションにより、ユーザーがデータを読み取ってから、そのデータが変更されていないかが確認されます。
ステートレス環境では、期限切れの(失効した)データを処理しないよう、特に注意する必要があります。失効したデータを処理しないための一般的な戦略は、オプティミスティック・ロックを実装し、オプティミスティック・ロックの値をオブジェクトに格納することです。この方法は、ステートレス・アプリケーションがオブジェクトをシリアライズする場合、またはオブジェクトの内容を代替形式でクライアントに送信する場合には、十分注意して行う必要があります。これらの場合、オプティミスティック・ロックの値を編集ページのHTTPコンテンツとしてクライアントに転送します。次に、任意の書込みトランザクションの戻り値を使用して、クライアントが処理を実行しているときに、データが変更されていないことを確認する必要があります。
オプティミスティック・バージョン・ロック・ポリシーまたはオプティミスティック・フィールド・ロック・ポリシーを使用できます。バージョン・ロック・ポリシーの使用をお薦めします。
@Version注釈を使用して、オプティミスティック・ロックの値として機能するエンティティ・クラスのバージョン・フィールドまたはプロパティを指定することで、JPA管理のオプティミスティック・ロックを有効化できます(推奨)。
バージョン・フィールドまたはプロパティを選択する場合、次の条件を満たす必要があります。
-
1つのエンティティに対してただ1つのバージョン・フィールドまたはプロパティがあること
-
プライマリ表に永続化されたプロパティまたはフィールドを選択すること
-
アプリケーションでバージョン・プロパティまたはフィールドを変更しないこと
詳細は、JPA仕様の11.1.45項「Table Annotation」を参照してください。
http://jcp.org/en/jsr/detail?id=338
注意:
フィールドまたはプロパティ・タイプは、数値型(Number、long、int、BigDecimalなど)またはjava.sql.Timestampである必要があります。EclipseLinkでは数値型の使用をお薦めします。
@Version注釈には属性はありません。@Version注釈では、EclipseLinkコンバータを使用することができます。前述の「デフォルトの変換およびコンバータ」を参照してください。
詳細は、JPA仕様の11.1.9項「Column Annotation」を参照してください。
MOXyマッピングの概念
XMLマッピングは、オブジェクトのデータ・メンバーを、構造がXMLスキーマ・ドキュメント(XSD)により定義されているXML文書のXML要素に変換します。
様々なXMLマッピング・タイプを使用して、XMLの単純および複合型の組合せにJavaオブジェクトの属性をマップできます。
クラスは複合型にマップされ、オブジェクトの関係はXML要素にマップされ、単純属性はテキスト・ノードとXML属性にマップされます。MOXyを使用する場合の真価は、オブジェクト属性をXML文書にマッピングする際に、XPath文を使用してXMLデータの場所を指定できることにあります。
EclipseLinkでは、クラスのディスクリプタに各クラスのXMLマッピングを格納します。EclipseLinkでは、ディスクリプタを使用してXML文書からマップされたオブジェクトをインスタンス化し、新規または変更済のオブジェクトをXML文書として格納します。
EclipseLinkには、JAXB仕様には定義されていないXMLマッピングが用意されています。MOXyの拡張機能には、EclipseLinkの注釈を介して使用できるものと、基礎となるメタデータに対するプログラムの変更が必要なものがあります。
MOXyに対するマッピングの概念については、『Developing JAXB Applications EclipseLink MOXy』に記載されています。次の章を参照してください。
EclipseLink MOXyランタイムに関する章の内容は次のとおりです。
-
JAXB注釈に代わる、EclipseLink XMLバインディング・ドキュメント。XMLバインディングは、マッピング情報を実際のJavaクラスから分離できるだけでなく、高度なメタデータにも使用できます。
-
JAXBContextの作成時に使用できる、何種類かのブートストラップ・オプション。
-
EclipseLinkメタデータの提供を担当する、MetadataSourceインタフェース。このインタフェースの実装の指定により、マッピング情報をアプリケーションの外部に保存して、アプリケーションのJAXBContextが作成またはリフレッシュされるときにマッピング情報を取得できるようになります。
-
スキーマの生成および検証。
-
マーシャリング・プロセス中およびアンマーシャリング・プロセス中に、イベント・コールバックを取得する何種類かのメカニズム。マップされたオブジェクトにコールバック・メソッドを直接指定するか、または別のListenerクラスを定義し、JAXBランタイムに登録できます。
-
XPathによるオブジェクトの問合せ。これは、従来のJavaアクセス・メソッドに代わる、オブジェクトの値の取得および設定方法です。EclipseLink MOXyでは、XPath文を使用して値にアクセスすることができます。EclipseLinkのJAXBContextには、XPathで値を取得および設定できるようにするための特殊なAPIがあります。
-
アイテムの一部のみがマップされている場合でもXML文書全体を保持できる、JAXB Binderインタフェースの使用。
単純な値のマッピングに関する章では、MOXyでマッピングを設定する初期タスクについて説明しています。
-
XML文書の最上位レベルのルートが何になるかをEclipseLinkに通知する、デフォルトのルート要素。
-
Javaクラスの名前空間の情報、およびすべての要素が名前空間に対して修飾されている必要があること。パッケージ、タイプまたはフィールド/プロパティ・レベルの要素を名前空間に対して修飾できます。
-
xsi:type属性、代替グループまたはMOXY固有の@XmlDiscriminatorNodeおよび@XmlDiscriminatorValue注釈を使用して、XMLで継承階層を指定する方法
単純な値のマッピングに関する章および特殊なスキーマ・タイプのマッピングに関する章は、Java値をXMLにマップする様々な方法を説明しています。
-
Java値はXML属性、テキスト・ノード、スキーマ・タイプまたはシンプル・タイプ・トランスレータにマップできます。
-
単純なJava値のコレクションは、テキスト・ノード、グループ化要素内のテキスト・ノード、リスト要素またはXmlAttributesまたはXmlValuesのコレクションにマップできます。
-
OXMメタデータを使用して1つのプロパティに複数のJavaマッピングを作成できます。ただし、読取り可能なマッピングはせいぜい1つです(それ以外は「書込み専用」です)。
-
Javaenumsは、@XmlEnum注釈と@XmlEnumValue注釈を使用してXMLにマップできます。
-
日付と時間: また、EclipseLink MOXyは、JAXB仕様で扱われていない次の型をサポートしています。java.sql.Date、java.sql.Timeおよびjava.sql.Timestamp。
-
unionファイル: EclipseLinkでXMLスキーマ・ユニオンなどのXML文書をアンマーシャリングする場合、正常な変換が行われるまで、union型のそれぞれが試行されます。現時点では、EclipseLinkは、注釈またはOXMメタデータを使用したunionのマッピングをサポートしていません。ただし、EclipseLinkのXMLカスタマイザを使用してマッピングを作成することはできます。
-
バイナリ形式: EclipseLinkでは、base64Binary(デフォルト)とhexBinaryという、2つの表現形式でのバイナリ・データのマーシャリングおよびアンマーシャリングをサポートしています。EclipseLink OXMで@XmlSchemaType注釈または<xml-schema-type>要素を使用して、目的のバイナリ形式を指定できます。
XMLデータ表現の理解
JPAからXMLへのマッピングに注釈を使用することは、常に最も効果的とはかぎりません。
たとえば、次の場合にはJAXBを使用しません。
-
サード・パーティのクラスにメタデータを指定する必要があるが、ソースにアクセスできない場合。
-
複数のXMLスキーマにオブジェクト・モデルをマップする必要がある場合。JAXBのルールでは、注釈を使用して複数のマッピングを適用することはできません。
-
オブジェクト・モデルにすでに多くの注釈(たとえば、JPA、Spring、JSR-303などのサービスから)が含まれていて、他の場所でメタデータを指定する必要がある場合。
これらの状況および類似の状況では、eclipselink_oxm.xml
ファイルを公開して、XMLデータ表現を使用できます。
XMLメタデータは、次の2つのモードで動作します。
-
注釈で指定されたメタデータに追加します。これは、次の場合に便利です。
-
XML表現のバージョンのひとつが注釈に定義されており、XMLメタデータを使用して将来のバージョンのメタデータを微調整する場合。
-
標準のJAXB注釈を使用し、かつMOXy拡張機能用のXMLメタデータを使用する場合。このようにすると、コンパイル時の依存関係がオブジェクト・モデルに新たに生じることはありません。
-
-
注釈メタデータを完全に置換します。これは、様々なXML表現にマップする必要がある場合に便利です。
オブジェクトとJSONのマッピングの概念
EclipseLink MOXyでは、JSON (JavaScript Object Notation)を対象とするオブジェクトの変換機能がサポートされます。
この機能は、RESTfulサービスを作成する場合に便利です(JAX-RSサービスはXMLとJSON両方のメッセージを受け取ることができます)。
EclipseLinkは、次のようなJSONの読取り時と書込み時のすべてのMOXyオブジェクト/XMLオプションに対応しています。
-
EclipseLinkの高度な拡張マッピング機能(JAXB仕様に対する追加)
-
外部バインディング・ファイルへのマッピングの格納
-
動的JAXBによる動的モデルの作成
-
マルチテナント・アプリケーションをサポートする拡張可能モデルの作成
EclipseLinkでは、JSON文書のマッピングに次のサポートが提供されます。
-
通常のJAXBでの使用に必要とされるもの以外は、JSONバインディングでコンパイル時の依存性は必要ありません。JSON文書としてMOXy外部バインディング・ファイルを書き込むこともできます。
-
XMLは単一のデータ型を保持しますが、JSONは文字列、数値、ブール値を区別します。EclipseLinkでは、これらのデータ型が自動的にサポートされます。
-
JSONでは属性は使用されず、@XmlAttribute注釈を使用してマップされたものはすべて要素としてマーシャリングされます。デフォルトでは、EclipseLinkによって属性および要素のイベントが両方ともトリガーされるため、マップされた属性または要素で値を処理できます。
-
EclipseLinkでは、ルート要素のないJSON文書がサポートされます。デフォルトで、@XmlRootElement注釈が存在しない場合、マーシャリングされたJSON文書にルート要素は含まれません。EclipseLinkでは、この動作をオーバーライドできます(JSON出力からルート要素を省略できます)。
-
JSONではネームスペースを使用しないため、すべてのネームスペースおよび接頭辞は、マーシャリングおよびアンマーシャリング時にデフォルトで無視されます。EclipseLinkでは、マーシャラおよびアンマーシャラに、ネームスペースと接頭辞のMap (またはNamespacePrefixMapperのインスタンス)を提供できます。ネームスペース接頭辞は、要素名の先頭に追加されて、マーシャリングされた文書に出現します。
-
デフォルトでは、JSONへのマーシャリング時に、EclipseLinkは空のコレクションを[ ]としてマーシャリングしますが、この動作をオーバーライドして、空のコレクションをまったくマーシャリングしないようにできます。
-
ルート・レベルのコレクションをマーシャリングおよびアンマーシャリングできます。
JSON文書に対するEclipseLinkサポートの詳細は、『Developing JAXB Applications EclipseLink MOXy』の「Using JSON Documents」を参照してください。