How to make the Genericdao class using Hibernate?

Asked

Viewed 13,163 times

13

I wanted to know how to make a generic Dao of a project, using Hibernate and JPA in java.

All this to not be mounting a DAO as follows for each object that will persist in the bank:

public class ProdutoDao {

    private final EntityManager em;

    @Inject
    public ProdutoDao(EntityManager em) {
        this.em = em;
    }

    public void adiciona(Produto produto) {
        em.getTransaction().begin();
        em.persist(produto);
        em.getTransaction().commit();
    }

    public void remove(Produto produto) {
        em.getTransaction().begin();
        em.remove(busca(produto));
        em.getTransaction().commit();
    }

    public Produto busca(Produto produto) {
        return em.find(Produto.class, produto.getId());
    }

    @SuppressWarnings("unchecked")
    public List<Produto> lista() {
        return em.createQuery("select p from Produto p").getResultList();
    }
}
  • These links can help you: http://wehavescience.com/2013/02/24/criando-um-dao-generico-com-hibernate/ and http://blog.caelum.com.br/brincando-com-generics-o-bizarregenericdao/. Good luck!

2 answers

12


public abstract class GenericDao<T, I extends Serializable> {

   @Inject
   protected EntityManager entityManager;

   private Class<T> persistedClass;

   protected GenericDao() {
   }

   protected GenericDao(Class<T> persistedClass) {
       this();
       this.persistedClass = persistedClass;
   }

   public T salvar(@Valid T entity) {
       EntityTransaction t = entityManager.getTransaction();
       t.begin();
       entityManager.persist(entity);
       entityManager.flush();
       t.commit();
       return entity;
   }

   public T atualizar(@Valid T entity) {
       EntityTransaction t = entityManager.getTransaction();
       t.begin();
       entityManager.merge(entity);
       entityManager.flush();
       t.commit();
       return entity;
   }

   public void remover(I id) {
       T entity = encontrar(id);
       EntityTransaction tx = entityManager.getTransaction();
       tx.begin();
       T mergedEntity = entityManager.merge(entity);
       entityManager.remove(mergedEntity);
       entityManager.flush();
       tx.commit();
   }

   public List<T> getList() {
       CriteriaBuilder builder = entityManager.getCriteriaBuilder();
       CriteriaQuery<T> query = builder.createQuery(persistedClass);
       query.from(persistedClass);
       return entityManager.createQuery(query).getResultList();
   }

   public T encontrar(I id) {
       return entityManager.find(persistedClass, id);
   }
}

I always use this one. See if it helps you.

Your DAO would look like this:

public class ProdutoDao extends GenericDao<Produto, Long> {
    public ProdutoDao() {
       super(Produto.class);
    }   
}
  • wouldn’t it be better to put the close/flush of the entityManager inside a Finally after a Try? if any exception occurs...

7

I use something similar to what was indicated by @Cassio Danilo. Only sometimes it is interesting that a DAO is implemented both via JPA and Adhoc (JDBC).

My suggestion is this::

  1. Create an interface for DAO that suggests the main interaction methods with the entity (CRUD)
  2. Create an abstract support class for each type of implementation: JPA and Adhoc.

It would look like this:

Dao.class

public interface Dao<E extends Serializable, I> {

    E consultarPorId(I id);

    void inserir(E entity);

    E atualizar(E entity);

    void excluir(E entity);

    List<E> consultarTodos();

}

Abstractjpadao.class

@Named
@Transactional(propagation = Propagation.MANDATORY)
public abstract class AbstractJPADao<E extends Serializable, I> extends AbstractJPASupport implements
    Dao<E, I> {

    private final Class<E> entityClass;

    protected AbstractJPADao(Class<E> entityClass) {
        this.entityClass = entityClass;
    }

    public CriteriaQuery<E> getCriteriaQuery() {
        return this.getEntityManager().getCriteriaBuilder().createQuery(entityClass);
    }

    @Override
    public void excluir(E entity) {
        this.getEntityManager().remove(entity);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<E> consultarTodos() {
    return this.getEntityManager().createQuery(
        String.format("from %s", this.entityClass.getName()))
        .getResultList();
    }

    @Override
    public E consultarPorId(I id) {
        return this.getEntityManager().find(entityClass, id);
    }

    @Override
    public void inserir(E entity) {
        this.getEntityManager().persist(entity);
    }

    @Override
    public E atualizar(E entity) {
        return this.getEntityManager().merge(entity);
    }

}

Abstractjpasupport.class

@Named
@Transactional(propagation = Propagation.MANDATORY)
public abstract class AbstractJPASupport {

    private EntityManager entityManager;

    public AbstractJPASupport() {

    }

    public CriteriaBuilder getCriteriaBuilder() {
        return entityManager.getCriteriaBuilder();
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }

    @PersistenceContext
    @Inject
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @PostConstruct
    protected void init() {
    checkState(this.entityManager != null,
        "Atencao! Entity Manager nao inicializado.");
    }
}

Pay attention to the detail of @Transactional(propagation = Propagation.MANDATORY). If you are using Spring, it is an interesting way to ensure a non-functional requirement so that your DAO does not run outside a transactional environment.

Now support for JDBC implementation:

Abstractjdbcdao.class

@Named
@Transactional(propagation = Propagation.MANDATORY)
public abstract class AbstractJDBCDao {

    @Inject
    private DataSource dataSource;

    private NamedParameterJdbcTemplate jdbcTemplate;

    private SimpleJdbcCall simpleJdbcCall;

    private SimpleJdbcInsert simpleJdbcInsert;

    public AbstractJDBCDao() {

    }

    @PostConstruct
    protected final void init() {
        checkState(this.dataSource != null,
            "Atencao! DataSource nao inicializado.");
        final JdbcTemplate rootJdbcTemplate = new JdbcTemplate(dataSource);

        this.jdbcTemplate = new NamedParameterJdbcTemplate(rootJdbcTemplate);
        this.simpleJdbcCall = new SimpleJdbcCall(rootJdbcTemplate);
        this.simpleJdbcInsert = new SimpleJdbcInsert(rootJdbcTemplate);
    }


    public final void setDataSource(final DataSource dataSource) {
        this.dataSource = dataSource;
    }

    protected final NamedParameterJdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    protected final SimpleJdbcCall getSimpleJdbcCall() {
        return simpleJdbcCall;
    }

    protected final SimpleJdbcInsert getSimpleJdbcInsert() {
        return simpleJdbcInsert;
    }

}

This implementation is based on Spring JDBC. It can be adapted to other frameworks. But the idea is to suggest that your data layer can implement more than one form of data access depending on your scenario.

I made a project available on Github which can be used as a reference to work with Spring + JPA + JDBC using Profiles to determine the type of data layer that will be used in the project. It is for reference only. If you have something to put, please leave in the comments.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.