現在、勉強で作成しているアプリケーションも上記の流れで行っていた。
O/RマッパーにはJPAを使って作成していて、そこで問題が発生。
まず、JPAにて良く紹介されているEntityのライフサイクルを紹介。
この中でmanaged状態になっているものと、removed状態になっているものがJPAエンジンのフラッシュのタイミングでDBに反映される。
このフラッシュのタイミングが都合の悪い場合がたまにある。早くフラッシュして欲しい場合は明示的にflushメソッドをコールすれば良いのだが、遅らせたい場合に困った。
今回の例だと以下の流れになるのだが、本来Cのタイミングでフラッシュして欲しいのだが、Bのタイミングでフラッシュされてしまった。
@一覧より更新対象を選択
↓
A選択されたデータの詳細を編集
↓
Bプレビュー画面を表示
↓
C更新処理を行う
さて、どうするか。パッと思いついた方法はとりあえずdetached状態にすることだ。
@のタイミングで選択後、clearメソッドにてdetached状態にする。で、そのままA、Bと進み、
Cのタイミングで再び、managed状態にしてみるという寸法だ。
結論から言うと、とりあえずうまく行ったのだけどスマートでない。
しかも、detached状態にするためにclearメソッドをコールするのはどうかと思う。
これでは全てのmanaged状態のオブジェクトがdetached状態になってしまう。
何か、もっと良い方法があると思い再び調査。
どうやら@BeginアノテーションにflushModeというものを設定できるようだ。
元々EntityManagerにはsetFlushModeというメソッドがあり、
javax.persistence.FlushModeType.AUTOと、javax.persistence.FlushModeType.COMMITを指定できる。
大雑把な違いは、クエリーの結果にmanaged状態のものを含めるか含めないかの違いくらいしか認識してない。
そして、@BeginアノテーションにflushModeとして指定できるものは以下のものがある。(パッケージが違うのに注目)
・org.jboss.seam.annotations.FlushModeType.AUTO
・org.jboss.seam.annotations.FlushModeType.COMMIT
・org.jboss.seam.annotations.FlushModeType.MANUAL
AUTOとCOMMITの場合は、結局は内部的にEntityManager#setFlushModeをコールして、AUTOと、COMMITを設定している。
で、Seamはもう1つMANUALというものを用意してくれていて、これが今回求めていたものだった。
これを指定することにより、明示的にflushメソッドをコールするまで、すべての書き込み動作は対話コンテキスト内にキューイングされるのだ。
気をつける点は、@〜Cの流れで通るメソッドの全てに@Begin(flushMode=FlushModeType.MANUAL)を指定しないと駄目なことくらいか?
今までO/RマッパーはiBATISくらいしか使ったことがないので、JPAは斬新で面白いけど、色々躓くなー。