Friday, September 17, 2010

Force JPA load Identity ID after Insert

When you have an ID into your Entity Classe from Database and that is Identity, if you do an insert action the ID of this Entity isn't reloaded by default with the ID that was generated by Database, through JPA.

A sample of an ID of Identity kind:

@Id
@Basic(optional = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "Id")
private Integer id;


To refresh the ID value with the ID that was generated by the Database on insert action, you need put more this below in your AbstractFacade.Create(EntityClass):

getEntityManager().flush();
getEntityManager().refresh(entity);


  • getEntityManager().flush() - Will do the commit to Database execute the insert action.

  • getEntityManager().refresh(entity) - Will refresh the entity object with a new ID that was inserted.


Full sample of the AbstractFacade.java:

package org.test.ejb;

import java.util.List;
import javax.persistence.EntityManager;

public abstract class AbstractFacade {
private Class entityClass;

public AbstractFacade(Class entityClass) {
this.entityClass = entityClass;
}

protected abstract EntityManager getEntityManager();

public void create(T entity) {
getEntityManager().persist(entity);
getEntityManager().flush();
getEntityManager().refresh(entity);
}

public void edit(T entity) {
getEntityManager().merge(entity);
}

public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}

public T find(Object id) {
return getEntityManager().find(entityClass, id);
}

public List findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}

public List findRange(int[] range) {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
javax.persistence.Query q = getEntityManager().createQuery(cq);
q.setMaxResults(range[1] - range[0]);
q.setFirstResult(range[0]);
return q.getResultList();
}

public int count() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
javax.persistence.criteria.Root rt = cq.from(entityClass);
cq.select(getEntityManager().getCriteriaBuilder().count(rt));
javax.persistence.Query q = getEntityManager().createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
}
}


If you publish your JPA Create action in a Web Services, you will need return to client side an Entity instance to client know what is the new ID. Cause the Entity instance of the Client side can't be refresh with changes inside Server.
Like:

@WebMethod(operationName = "create")
public BusinessEntity create(@WebParam(name = "businessEntity")
BusinessEntity businessEntity) {
ejbRef.create(businessEntity);
return businessEntity;
}


5 comments:

  1. Hi Eduardo, my name is Jayson Monterroso I'm from Guatemala, I live in Costa Rica, I'm adventist, I was looking for the HinĂ¡rio Adventista ~ Android Application and found that you are the developer, I am developer too, but I don't have any experience with android but I really like learn so, I would like start translating your application to spanish if you like for me would be a pleasure. Have a great day, and blessings.

    ReplyDelete
  2. I love to see it in spanish God bless you all

    ReplyDelete
  3. Thanks so much for this post.
    It really helped me.
    Thanks!!!!

    ReplyDelete
  4. hi,
    the codes
    getEntityManager().flush();
    getEntityManager().refresh(entity);
    didn't work for me. But I am accessing the EJB object via a Remote interface. Do you know other way to get id value.

    Thanks.

    ReplyDelete
  5. hi!
    even in remote mode if you do:
    getEntityManager().persist(entity);
    getEntityManager().flush();
    getEntityManager().refresh(entity);
    System.out.println(((YOURENTITY)entity).getId());
    The correct ID should be showed. After this you need track where lost the ID...
    I don't have another idea for now.

    ReplyDelete