138

I'm using JPA (EclipseLink) and Spring. Say I have a simple entity with an auto-generated ID:

@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;

     // ...
}

In my DAO class, I have an insert method that calls persist() on this entity. I want the method to return the generated ID for the new entity, but when I test it, it returns 0 instead.

public class ABCDao {
    @PersistenceContext
    EntityManager em;

    @Transactional(readOnly=false)
    public int insertABC(ABC abc) {
         em.persist(abc);
         // I WANT TO RETURN THE AUTO-GENERATED ID OF abc
         // HOW CAN I DO IT?
         return abc.id; // ???
    }
}

I also have a service class that wraps the DAO, if that makes a difference:

public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         return abcDao.insertABC(abc);
    }
}
sura2k
  • 7,365
  • 13
  • 61
  • 80
  • Similar one, can refer http://stackoverflow.com/q/3328813/366964 – Nayan Wadekar Mar 16 '12 at 05:51
  • Thanks for the answers. And as a tricky solution (not a JPA) we can use another unique id like unix timestamp. – sura2k Mar 19 '12 at 16:16
  • 1
    possible duplicate of [When does the JPA set a @GeneratedValue @Id](http://stackoverflow.com/questions/9087848/when-does-the-jpa-set-a-generatedvalue-id) – Raedwald Jan 20 '15 at 07:56
  • Please refer the below link, looks like the same issue https://stackoverflow.com/questions/9732453/jpa-returning-an-auto-generated-id-after-persist – anurag saxena Sep 25 '20 at 09:56

7 Answers7

221

The ID is only guaranteed to be generated at flush time. Persisting an entity only makes it "attached" to the persistence context. So, either flush the entity manager explicitely:

em.persist(abc);
em.flush();
return abc.getId();

or return the entity itself rather than its ID. When the transaction ends, the flush will happen, and users of the entity outside of the transaction will thus see the generated ID in the entity.

@Override
public ABC addNewABC(ABC abc) {
    abcDao.insertABC(abc);
    return abc;
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 11
    NB: this needs to anotate the id field with `@GeneratedValue` - whatever that entails – Mr_and_Mrs_D Feb 08 '14 at 20:12
  • Can u please explain the issues in trying to achieve this with composite id http://stackoverflow.com/questions/31362100/explain-behaviors-in-mapping-auto-incremented-composite-id-sequence-with-hiberna – rakesh99 Jul 22 '15 at 05:45
  • Is there a performance penalty (or any other negative effects) of manually flushing after persisting? – Craig Otis Apr 29 '16 at 12:09
  • 3
    Yes, there is: unnecessary roundtrip to the database if the transaction ends up being rollbacked, potential exceptions if the persisted entity (or other flushed entities) is not in a valid state yet. A sequence or uuid generator is simpler and more efficient, and doesn't have these problems because the ID is generated and assigned before the entity is written to the database. – JB Nizet Apr 29 '16 at 12:23
  • 2
    @JBNizet, do you need to return the instance or is the passed reference still valid? I mean, does `insertABC` create a new object? Or modify the old one? – ryvantage Oct 13 '16 at 03:10
  • `@Override` `public boolean addNewABC(ABC abc) {` `return abcDao.insertABC(abc);` `}` this I believe will return the id by parameter reference and does not need a return object; – André Luís Tomaz Dionisio Nov 30 '16 at 11:17
  • @Override public void addNewABC(ABC abc) { abcDao.insertABC(abc); } is this valid ? – lakshman sai Jan 22 '19 at 13:38
14
@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;   
}

check that @GeneratedValue notation is there in your entity class.This tells JPA about your entity property auto-generated behavior

utkal patel
  • 1,321
  • 1
  • 15
  • 24
6

This is how I did it:

EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
long id = object.getId();
entityManager.close();
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
  • 1
    Its not working giving zero as a Return after persisting the data into table. either refresh is not working at this case .. What should i do for this. please suggest a way... Thank you – Vikrant Kashyap Jun 13 '16 at 06:57
  • 1
    @VikrantKashyap Please post a new question with small code and mention me so I can take a look. – Koray Tugay Jun 13 '16 at 07:03
2

You could also use GenerationType.TABLE instead of IDENTITY which is only available after the insert.

James
  • 17,965
  • 11
  • 91
  • 146
  • 2
    Just a word of caution. When I tried GenerationType.TABLE, it created a separate table named hibernate_sequences and restarted the sequence from 1. – SriSri May 04 '18 at 03:37
0

Another option compatible to 4.0:

Before committing the changes, you can recover the new CayenneDataObject object(s) from the collection associated to the context, like this:

CayenneDataObject dataObjectsCollection = (CayenneDataObject)cayenneContext.newObjects();

then access the ObjectId for each one in the collection, like:

ObjectId objectId = dataObject.getObjectId();

Finally you can iterate under the values, where usually the generated-id is going to be the first one of the values (for a single column key) in the Map returned by getIdSnapshot(), it contains also the column name(s) associated to the PK as key(s):

objectId.getIdSnapshot().values()
emecas
  • 1,586
  • 3
  • 27
  • 43
-2

This is how I did it. You can try

    public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         ABC.setId(0);
         return abcDao.insertABC(abc);
    }
}
-3
em.persist(abc);
em.refresh(abc);
return abc;
Andrey
  • 676
  • 2
  • 8
  • 12
  • This method did not work for me. Got this error: javax.persistence.PersistenceException: org.hibernate.HibernateException: this instance does not yet exist as a row in the database] – rtcarlson Jun 17 '13 at 21:56
  • 1
    @rtcarlson, yes this will not work. if you're creating a new object, what you need is `em.flush()` not `em.refresh(abc)`. – Ibrahim Dauda Dec 30 '15 at 01:24