27

I am looking a smart and easily readable way to get the id of a persisted entity using JPA. The id is an Integer.

One could think of the following solutions:

  1. Without using GeneratedValue strategy. This requires looking for a free id before persisting, then putting it into the entity to be persisted: cumbersome, but works.
  2. With a GeneratedValue strategy. The persistence provider will take care of the id generation. This looks smarter, but how to get the id?

See below for solution 2

MyEntity en = new MyEntity();
en.setName("My name");
em.persist(en);
System.out.println(en.getId());

This prints a null id!

Any suggestions? I am using MySql, EclipseLink, but need a portable solution.

perissf
  • 15,979
  • 14
  • 80
  • 117

1 Answers1

59

persist is not guaranteed to generate the ID. The ID is guaranteed to be generated at flush time only. So if you really need the ID before the transaction ends (and the entity manager is thus flushed), call flush() explicitely to get the ID:

MyEntity en = new MyEntity();
en.setName("My name");
em.persist(en);
em.flush();
System.out.println(en.getId());
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • @JB Nizet, how can I get id before `persist()` method? I am looking forward it because of I would like change custom id format? – Zaw Than oo Mar 15 '13 at 03:36
  • 1
    @CycDemo: you can't, unless you generate it by yourself. – JB Nizet Mar 15 '13 at 06:55
  • @JBNizet Where is the source of the statement "persist is not guaranteed to generate the ID"? In the JPS Spec (JSR ) I read the following two statements (Chapter 3.2): - A managed entity instance is an instance with a persistent identity - The semantics of the persist operation, applied to an entity X are as follows: If X is a new entity, it becomes managed. ... *If I interpret that word by word, I would say that the spec demands that the Id is set after calling persist()*. That is also the behaviour of Hibernate. – jbandi Nov 11 '14 at 16:31
  • http://docs.jboss.org/hibernate/core/4.3/manual/en-US/html/ch11.html#objectstate-makingpersistent – JB Nizet Nov 11 '14 at 16:34
  • @JBNizet Wow that was a quick answer :-). However I do not completely agree that this link is the definitive answer. It references the Hibernate documentation. Hibernate seems to make a difference between persist() and save(). JPA does not provide this difference, so the semantics must not necessarily be the same. And if I read the JSR-338 I would say it demands that Id is set after calling persist(). – jbandi Nov 11 '14 at 16:42
  • The spec also says that the PostPersist(), in which the ID is available, may only be called at flush time. The javadoc of PersistenceUnitUtil.getIdentifier() also says that a generated id is not guaranteed to the database insert has occurred. JPA doesn't have a save() method, so obviously, it can't make a distinction between save() and persist(). – JB Nizet Nov 11 '14 at 16:44
  • @JBNizet The fact that EclipseLink is the reference implementation gives you right, of course. But Hibernate actually behaves different than EclipseLink. Hibernate actually performs an SQL insert when calling persist() and not when calling flush()/commit() in the case of the IdentityGenerationStrategy defining that the DB generates the Id. So I would guess Hibernate maps the JPA-persist() to the Hibernate-save(). – jbandi Nov 11 '14 at 16:54
  • 1
    This works only with em.persist(en), but not with em.merge(en). Using merge it returns null. – Brain Dec 05 '14 at 11:02