JPA - Returning an auto generated id after persist

2019-01-06 09:18发布

问题:

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);
    }
}

回答1:

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;
}


回答2:

@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



回答3:

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



回答4:

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();


回答5:

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()


回答6:

em.persist(abc);
em.refresh(abc);
return abc;


标签: java jpa