JPAを使ってエンティティをINSERTし、更にINSERTしたエンティティの主キーを取得する必要があったとします。
例えば次のようなコードを考えてみます。
@Entity public class Foo { // AUTO INCREMENTなカラムIDを主キーとしている @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; ... } public class FooDAO { /** * FooをINSERTし、生成された主キーを返す。 */ public long persistFoo(EntityManager em, Foo foo) { //Fooを実際にINSERTする (→ウソ) em.persist(company); //生成された主キーを取得する (→ウソ。常に0が返る) final long generatedFooId = foo.getId(); return generatedFooId; } ... }
このとき、FooDAO#persistFooは意図したとおりには動作しません。
具体的には、persistFooが返す値は常に0となります。すなわち主キーを取得できていないわけです。
その理由は、EntityManagerの更新系メソッド(persist, merge, delete)は、呼び出された時点ですぐにDML文を発行するわけではないからです。
JPAのデフォルトでは、コミット直前にまとめてSQLを発行する仕様になっています。
つまり、例えばEntityManager#persistなら『INSERT対象とするエンティティにマークを付ける』だけなのです。
こちらの記事(IBM Developerworks)も参考にしてください。
この場合は、EntityManager#flushを使用して強制的にSQLを実行させればOKです。
修正したコードは次のようになります。
@Entity public class Foo { // AUTO INCREMENTなカラムIDを主キーとしている @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; ... } public class FooDAO { /** * FooをINSERTし、生成された主キーを返す。 */ public long persistFoo(EntityManager em, Foo foo) { //FooをINSERTすることをマークする em.persist(company); //強制的にFooをINSERTする em.flush(); //生成された主キーを取得する final long generatedFooId = foo.getId(); return generatedFooId; } ... }