Gostaria de compartilhar com voces uma ideia que tive.
Cansado de implementar DAOs com trocentos metodos sobrecarregados, tipo:
List findAll();
List findAll(String orderBy);
List findAll(int firstResult, int maxResults);
List findAllByExample(Example o);
T findOneByExample(Example o);
etc. etc. Sem contar as possiveis combinacoes entre eles…
Resolvi refatorar um velho DAO e surgiu o seguinte:
public class Dao<T, K extends Serializable> {
protected Criteria c;
protected Session session;
protected Class<T> persistentClass;
public Dao(Session session, Class<T> persistentClass) {
this.session = session;
this.persistentClass = persistentClass;
}
public Dao<T, K> find() {
c = session.createCriteria(persistentClass);
return this;
}
public Dao<T, K> withActiveStatus(Boolean active) {
c.add(Restrictions.eq("active", active));
return this;
}
public Dao<T, K> withOrderByAsc(String propertyName) {
c.addOrder(Order.asc(propertyName));
return this;
}
public Dao<T, K> withOrderByDesc(String propertyName) {
c.addOrder(Order.desc(propertyName));
return this;
}
public Dao<T, K> withExample(T example) {
c.add(Example.create(example).enableLike(MatchMode.ANYWHERE).ignoreCase());
return this;
}
public Dao<T, K> withResults(int first, int max) {
c.setFirstResult(first);
c.setMaxResults(max);
return this;
}
public int count() {
c.setProjection(Projections.rowCount());
return (Integer) c.uniqueResult();
}
@SuppressWarnings("unchecked")
public List<T> all() {
return c.list();
}
@SuppressWarnings("unchecked")
public T one() {
return (T) c.uniqueResult();
}
}
public interface BaseDAO {
/*
* Ações possíveis feita com CRUD. Os métodos cujos parâmetros
* são do tipo java.util.List, são enviados em massa, ou seja,
* os dados são processados e armazenados e apenas no final o
* aplicativo lança o commit. Para grande massa de dados é mais
* viável pois o tempo de processo é muito maior quando abre apenas
* uma conexão e aplica apenas uma ação de persistencia
* */
public T remove(T object) throws Exception;
public T persist(T object) throws Exception;
public T update(T object) throws Exception;
public List<T> update(List<T> object) throws Exception;
public List<T> persist(List<T> list) throws Exception;
public List<T> remove(List<T> object) throws Exception;
/*
* Aqui se aplica todos os tipos de buscas possível para se fazer
* dentro de uma aplicação padrão.
* */
public List<T> findAll() throws Exception;
public T load(Object obj) throws Exception;
Engraçado como ficamos sempre presos a conceitos que aprendemos no passado. E é muito difícil sair desses conceitos. Eu sempre fiz repositories baseado em MyRepository.find, MyRepository.load, MyRepository.store, MyRepository.delete… (uso o termo repository ao invés de DAO, assunto já discutivo no guj)
No meu caso eu uso os repositories como local stateless session beans, e infelizmente parece que não funcionaria bem no meu caso, pois o atributo Criteria estaria em shared-mode, já que são stateless beans.
Antes de ler, os métodos getDdi() e getDdd() aparecem de forma dinamicas e são oriundos da classe Telefone.class… qualquer refactory na classe Teleofne é relfetido na consulta, pois não uso strings. Sempre apos chamar uma propriedade do restrict todos os método da classe do Criterio aparecem.
infelismente não da pra fazer uma query continua, pois as propriedades do Telefone não tem como retornar para o criteira… mas fica de facil entendimento…
Esse meu criteria já tem boa parte dos métodos do hibernate
Criteria<Telefone> query = Criteria
.forClass(Telefone.class)
.setFirstResult(0)
.setMaxResults(20);
Restriction<Telefone> restrict = query.addRestriction();
restrict.isEquals(55).getDdi();
restrict.isBetween(83, 85).getDdd();
query.addOrder().ascIgnoreCaseBy().getNumero();
//aqui vem a lisa dos telefones do ddi 55 com ddd entre 83 a 85
List<Telefone> telefones = genericDao.list(query);
//poderia ter usado genericDao.find(query); para encontra o primeiro