How to make the GenericDAO class using Hibernate?

12

I wanted to know the best way to do a generic Dao of a project, using Hibernate and JPA in Java.

That's all to avoid setting up a DAO for each object that will persist in the database:

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();
    }
}
    
asked by anonymous 21.07.2015 / 04:36

2 answers

11
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. See if it helps.

Your DAO would look like this:

public class ProdutoDao extends GenericDao<Produto, Long> {
    public ProdutoDao() {
       super(Produto.class);
    }   
}
    
21.07.2015 / 15:06
7

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

My suggestion is as follows:

  • Create an interface to DAO that suggests the main interaction methods with the entity (CRUD)
  • Create an abstract support class for each implementation type: 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.");
        }
    }
    

    Watch out for the detail of @Transactional(propagation = Propagation.MANDATORY) . If you are using Spring, it is an interesting way to ensure a non-functional requirement for your DAO not to run outside of a transacted 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. 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 have made available in GitHub a project that can be used as a reference to work with Spring + JPA + JDBC using Profile s 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 it in the comments.

        
    21.07.2015 / 15:49
    PHP + Delphi (Pascal), issue real-time warnings ___ ___ erkimt Performance: string "concatenated" or all on the same line? ______ qstntxt ___

    I have a loop with thousands of results that renders a table. The string is mounted through the StringBuilder in this way (example snippet):

    %pre%

    Can there be any performance improvement if I put the whole code in one line, as below?

    %pre%

    And if it were a concatenation, such as the following code?

    %pre%

    More advanced explanations of how language works are welcome.

        
    ______ azszpr7738 ___

    The best will always be to keep in a String that is unique at compile time rather than at runtime.

    And, believe it or not, in C # you can use line breaks in a single String using the character %code% (at) at the beginning of it.

    %pre%

    Also, according to this topic in SO , if you concatenate String literals in a same command, they will be concatenated at compile time, then it would give the same effect on runtime performance something like:

    %pre%

    Using %code% to concatenate String literals will decrease program performance, since it will prevent the compiler from optimizing literals.

    On the other hand, if the compiler can not know the size of the String at compile time, for example if we concatenate variables, %code% is usually faster than directly concatenating the values. I say "generally" because I do not really know how much the compiler or CPU would be able to optimize certain exceptional cases.

        
    ______ azszpr7751 ___

    In case of substituting multiple calls from %code% to only one, the gain will be minimal.

    On one occasion, working with the class %code% , I noticed a great improvement in performance when booting the %code% with a size sufficient to store the entire result. I did this using two routines, one to count the required size, and another to build the string.

    To initialize the StringBuilder with a size simply pass an integer in the con- tractor:

    %pre%     
    ______ azszpr21973 ___

    It has been properly said that the best way is to use a single %code% in the case presented. It's fast and legible.

    But if there is a reason to do sequential concatenation, it can be used without performance problems. It ends up becoming a single %code% at compile time. The only problem is being less readable.

    There is optimization of the compiler in many cases. But not at all. If all of the% s sizes involved are not known, there is not so much optimization. In these cases the optimization only transforms the concatenations in the %code% method. It is certainly better because it avoids unnecessary allocations, but the size calculation is still needed.

    Although the %code% property is of type %code% , I have doubts if it can be so optimized.

    If it is useful a %code% may be appropriate and not have a performance impairment. It may even be faster than a method %code% of %code% . When you know the total size required for all% s of% s in a simple way, possibly as a constant literal, %code% is very fast. Internally %code% uses a %code% so you find that the former is faster that the second one does not make sense. Of course, in cases that have only 4% with% s the concatenation is made simpler without %code% .

    But so far little has been added to what has been said in the other answers.

    Alternative: Resources

    There are cases to make work easier, the text should not be in the code. It should be in an external file, when this is pertinent, or be in Resources . It may be easier to maintain in this and it is very fast in the second case.

    For everything there is the best solution applied. This is a case that easier maintenance can be more important than performance. In case of catching the resource the performance will not be much affected either. And even if it is, it will not create problem for the application. This performance concern makes sense for cases of extreme strings manipulations . In the case of file access the performance will obviously be affected by access to mass memory. But it will still not affect the application. Of course this solution should only be chosen when you want to be able to change the text easily after compilation, when you want to give this freedom to the user.

        
    ___