8.4.6 永続化コンテキストからのエンティティの切り離しとmerge操作
永続化コンテキストから切り離されたエンティティをdetached状態のエンティティといいます。エンティティは次のタイミングでdetached状態になります。
-
トランザクションスコープの永続化コンテキストでのトランザクションをコミットしたとき
-
トランザクションのロールバックを実行したとき
-
永続化コンテキストをクリアしたとき(EntityManager.clear()を呼び出したとき)
-
EntityManagerをクローズしたとき
-
エンティティのシリアライズおよびエンティティの値渡しをしたとき
切り離されたエンティティのインスタンスは,永続化や取得をした永続化コンテキストの外で存在し続けます。エンティティの状態とデータベースの状態は同期されません。
(1) detached状態のエンティティへのアクセス
アプリケーションは永続化コンテキストの終了後でも,detached状態のエンティティにアクセスできます。この場合,エンティティのフィールドおよび関連先は,フェッチ済みである必要があります。detached状態のエンティティでフェッチされていないフィールドおよび関連先のエンティティにはアクセスできません。なお,フィールドに指定する@Basicには常にFetchType.EAGERが適用されるため,関連先のエンティティやフィールドの情報が取得済みとなります。
リレーションシップではdetached状態のエンティティからアクセスするには,次に示すどれかの条件を満たす必要があります。
-
find()で取得されたエンティティインスタンスであること
-
クエリを使って取得されたエンティティまたはFETCH JOIN節で明示的に要求されたエンティティであること
-
プライマリキーでない永続状態のインスタンスをアプリケーションでアクセス済みであること
-
fetch=EAGERと指定された関連をたどって別の有効なエンティティから取得済みのエンティティであること
利用できないインスタンスへのアクセス,および利用できるインスタンスの無効なステートへのアクセスを行った場合は,例外が発生します。ただし,CJPAプロバイダでは,FetchType.LAZYを指定した場合,EntityManagerの終了後にdetached状態になっていても,フェッチされていないフィールドおよび関連先エンティティにアクセスすると,データベースから値を取得して,内容を参照することができる場合があります。
(2) エンティティのmerge処理
EntityManagerのmergeメソッドの呼び出し,またはmerge処理のカスケードによって,detached状態のエンティティをEntityManagerで管理される永続化コンテキストにマージできます。
次の表にmerge処理でのエンティティの状態遷移を,エンティティAの状態ごとに示します。
エンティティAの状態 |
状態遷移の結果 |
---|---|
new |
managed状態のエンティティA'が新しく作成されて,エンティティAの状態がエンティティA'にコピーされます。mergeの引数のエンティティはnewのままであることに注意してください。 |
managed |
merge操作は無視されます。しかし,エンティティAからほかのエンティティへのリレーションシップのcascade属性に,MERGEまたはALLが指定されている場合,エンティティAが参照するエンティティにmerge操作が伝播されます。 |
detached |
エンティティAの状態が,同じIDを持つすでに存在している管理されたエンティティA'にコピーされます。または,エンティティAのコピーである新しいmanaged状態のエンティティが作成されます。mergeの引数のエンティティはdetached状態のままであることに注意してください。 |
removed |
merge操作によって,IllegalArgumentExceptionが発生します。または,トランザクションのコミットに失敗します。エンティティAの状態はremoved状態のままであることに注意してください。 |
JPA仕様では,フェッチされていないことを意味するLAZYにマークされたフィールドはマージのときに無視されます。ただし,CJPAプロバイダでは,@BasicはEAGERとして動作するため,リレーションシップでないすべてのフィールドはマージ処理の対象となります。
また,Version列がエンティティで使われている場合は,マージ操作とそのあとに呼ばれるフラッシュおよびコミット処理時に,エンティティのバージョンチェックを実行します。Version列が存在しない場合,merge操作ではエンティティのバージョンチェックは実行されません。詳細については,「8.10.1 楽観的ロックの処理」を参照してください。
なお,CJPAプロバイダでは,ほかベンダとの間で,エンティティのマージ処理によって永続化コンテキストに戻すという処理はサポートしていません。
(3) 注意事項
-
CJPAプロバイダの場合,トランザクションスコープの永続化コンテキストでは,managed状態のエンティティはトランザクションのコミットによってdetached状態になります。一方,拡張された永続化コンテキストでは,managed状態のエンティティは管理されたままとなります。
-
トランザクションスコープでも拡張された永続化コンテキストでも,トランザクションをロールバックすると,すべての存在しているmanaged状態のインスタンスとremoved状態のインスタンスは,detached状態になります。インスタンスの状態は,トランザクションがロールバックされた時点の状態です。
-
トランザクションをロールバックすると,永続化コンテキストの状態はロールバックした時点の状態になるため,データベースの状態と矛盾します。なお,CJPAプロバイダの場合は,バージョン属性の状態と生成された状態は矛盾した状態になるため,merge操作などを行うと例外になることがあります。