Search code examples
javajpacdidaojava-ee-8

How to implement a generic DAO with the same Entity Manager in java EE 8


I'm a begginer in Java EE and in JPA. In the past I have been creating a simple web-project, and I have implemented a generci DAO pattern without CDI, handling the Enitiry Manager.I know that diffrent EntityManager can use the same persistent context but because persistent context is a black box for me, I inject in the DAO constractor one EntityManager passing it as argument.I use this aproach for two reasons:

  1. Seperate the operation that has to do with diffrent entites.
  2. Deal with concurrency problems because all operation will be handeld in the same EntityManager and Trasanction

Here is the code of generic DAO:

GenericDAO

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

public abstract class GenericDAO<T> {

    protected final Class<T> persistentClass;
    protected final EntityManager em;

    public GenericDAO(EntityManager em, Class<T> persistencClass) {
        this.persistentClass = persistencClass;
        this.em = em;
    }

    public List<T> find(int id) {
        List<T> list;
        Query query = em.createQuery("select e from " + persistentClass.getSimpleName() + " e" + " where e.id =:id").setParameter("id", id);
        list = query.getResultList();
        return list;
    }

    public List<T> findAll() {
        List<T> list;
        Query query = em.createQuery("select e from " + persistentClass.getSimpleName() + " e");
        list = query.getResultList();
        return list;
    }

    public void create(T entity) {
        em.persist(entity);
    }

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

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

Actual implementation of generic DAO, code below:

UserDAOImpl

import java.util.List;
import entities.User;
import javax.persistence.EntityManager;
import javax.persistence.Query;

public class UserDAOImpl extends GenericDAO<User> {
     public UserDAOImpl(EntityManager em) {
           super(em, User.class);
     } 
}

TagDAOImpl

import entities.Tag ;
import java.util.List ;
import javax.persistence.EntityManager ;
import javax.persistence.Query ;

public class TagDAOImpl extends GenericDAO<Tag> {

    public TagDAOImpl(EntityManager em) {
        super(em, Tag.class);
    }
}

Now I want to implement the same pattern using Java EE injection of EntityManager. After a good search I found out the same solution like the below:

GenericDAO In Java ee

    public abstract class BaseDAO<T extends AbstractEntity> {

    private Class<T> entityClass() {
        @SuppressWarnings("unchecked")
        ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
        return (Class<T>) parameterizedType.getActualTypeArguments()[0];
    }

    protected abstract EntityManager entityManager();

    private final String SELECT_ALL = "SELECT e FROM ";
    private final String SELECT_COUNT = "SELECT COUNT(e) FROM ";
    private final String INSTANCE = " e";

    public List<T> findAll() {
        return entityManager()
                .createQuery(SELECT_ALL + entityClass().getSimpleName() + INSTANCE)
                .getResultList();
    }

    public Long count() {
        Object resulet = entityManager()
                .createQuery(SELECT_COUNT + entityClass().getSimpleName() + INSTANCE)
                .getSingleResult();
        return (Long) resulet;
    }
}

Actual implementation of generic DAO in Java ee, code below:

UserDAO

@Stateless
public class UserDAO extends BaseDAO<User> {

    @Inject
    protected EntityManager entityManger;

    @Override
    protected EntityManager entityManager() {
        return this.entityManger;
    }
}

TagDAO

@Stateless
public class TagDAO extends BaseDAO<Tag> {

    @Inject
    protected EntityManager entityManger;

    @Override
    protected EntityManager entityManager() {
        return this.entityManger;
    }

}

My problem here is that if I inject EntityManager in UserDAO and TagDAO, I have two diffrent instances of EntityManager. Will this be a problem if I want to persist a user and update a tag? Can I have such an example? Including the advantages and disadvantages.


Solution

  • First of all, you may add the @Inject private EntityManager into your GenericDAO class, applying DRY concepts. The usage of EntityManager and it's uniqueness will depend mainly of the scope chosen on you production methods. If you are sure all requests will be handled in a @RequestScoped environment, you may produce the EntityManager with this scope and all your DAOs will share the same bean as long they are at the same request.

    To produce a EntityManager with a request scope, you may use a CDI bean and a producer field or method, such as:

    @ApplicationScoped
    public class EntityManagerProducer implements Serializable {
    
        @Produces
        @RequestScoped
        // @MyBusinessDatabase // A qualifier so you can select different databases
        @PersistenceContext
        private EntityManager entityManager;
    
    }
    

    You may also use a @Dependent pseudo-scope. In this case, each entityManager injected will be unique to the injected bean. Please check this and this. As EntityManager is a lightweight entity (when opposed to an EntityManagerFactory), there is little overhead in using such scope, and we have, as an advantage when compared to @RequestScoped beans, the possibility to use the same bean in non-request operations, such as asynchronous or automated server-side calls.

    I've been using @Depended scoped entity managers for quite some time now, with different JPA implementations (Eclipselink and OpenJPA) without any issues but the ordinary optimistic lock exception when one given entity instance is updated by too many threads at the same time. When the case is critical, you may use a pessimistic approach to handle these cases.