Bom, no blog da Caelum a um tempo atras fizeram um POST sobre um DAO genérico, meio bizarro …
Bom, eu uso um DAO genérico a algum tempo, mas o meu DAO genérico tm algumas features a mais do que o mostrado no post da caelum …
Neste exemplo eu ja deixo os metodos para fazer um query by example prontinho, usando a API de criteria do Hibernate …
bom, chega de enrolação, vamos a alguns exemplos …
primeiro, crio uma interface para este DAO …
package br.com.techoffice.site.dao;
import java.io.Serializable;
import java.util.List;
public interface TOBaseDao<T, PK extends Serializable> {
public Class getObjectClass();
public T save(T object);
public T load(PK primaryKey);
public T get(PK primaryKey);
public List listAll();
public List findByExample(final T example);
public T findOneByExample(final T example);
public List listAll(final int first,final int max);
public int listAllPageCount();
public List findByExample(final T example,final int first,final int max);
public int findByExamplePageCount(final T example);
public void update(T object);
public void delete(T object);
public void rebind(T object);
}
onde o método getObjectClass() deve retornar a classe de trabalho deste DAO, a mesma passada no parâmetro T quando a interface for estendida …
e a implementação desta interface, fica mais ou menos assim:
package br.com.techoffice.site.dao.impl; import java.io.Serializable; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.Criteria; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.criterion.Example; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Example.PropertySelector; import org.hibernate.type.Type; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import br.com.techoffice.site.dao.TOBaseDao; import br.com.techoffice.site.dao.TODaoListener; @Transactional(propagation = Propagation.REQUIRED, timeout = 20) public abstract class TOBaseHibernateDaoextends HibernateDaoSupport implements TOBaseDao<T, PK>, PropertySelector { private static final Log logger = LogFactory.getLog(TOBaseHibernateDao.class); private final Class objectClass; public TOBaseHibernateDao(final Class objectClass) { this.objectClass = objectClass; } @SuppressWarnings("unchecked") public Class getObjectClass() { return objectClass; } public int findByExamplePageCount(final T example) { final List l = findByExample(example); final Integer i = new Integer(l.size()); return i.intValue(); } public int listAllPageCount() { final List l = listAll(); final Integer i = new Integer(l.size()); return i.intValue(); } /* * (non-Javadoc) * * @see br.ufrgs.hcpa.template.dao.GetNetBaseDao#findOneByExample(T) */ public T findOneByExample(final T example) { final List res = findByExample(example, 0, 1); if ((res != null) && (res.size() == 1)) { return res.get(0); } else { return null; } } public T save(final T object) { try { final Session s = getSession(false); s.save(object); s.flush(); return object; } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } public void update(final T object) { try { final Session s = getSession(false); s.update(object); s.flush(); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } public void rebind(final T object) { try { getSession(false).refresh(object); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } public void delete(final T object) { try { getSession(false).delete(object); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } @SuppressWarnings("unchecked") public T load(final PK primaryKey) { try { final Session s = getSession(false); final Object o = s.load(objectClass, primaryKey); return (T) o; } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } @SuppressWarnings("unchecked") public T get(final PK primaryKey) { try { final Session s = getSession(false); final Object o = s.load(objectClass, primaryKey); return (T) o; } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } @SuppressWarnings("unchecked") public List listAll() { try { final Session s = getSession(false); final Criteria c = s.createCriteria(objectClass); addOrderToCriteria(c); return c.list(); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } @SuppressWarnings("unchecked") public List findByExample(final T example) { try { final Session s = getSession(false); final Criteria c = s.createCriteria(objectClass); c.add(Example.create(example).enableLike(MatchMode.ANYWHERE).ignoreCase().setPropertySelector(this)); addOrderToCriteria(c); addPropertiedToCriteria(c, example); return c.list(); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } protected void addPropertiedToCriteria(final Criteria c, final T example) { } @SuppressWarnings("unchecked") public List findByExample(final T example, final int first, final int max) { try { final Session s = getSession(false); final Criteria c = s.createCriteria(objectClass); c.add(Example.create(example).enableLike(MatchMode.ANYWHERE).ignoreCase().setPropertySelector(this)); addPropertiedToCriteria(c, example); addOrderToCriteria(c); if (first != 0) { c.setFirstResult(first); } if (max != 0) { c.setMaxResults(max); } return c.list(); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } @SuppressWarnings("unchecked") public List listAll(final int first, final int max) { try { final Session s = getSession(false); final Criteria c = s.createCriteria(objectClass); addOrderToCriteria(c); if (first != 0) { c.setFirstResult(first); } if (max != 0) { c.setMaxResults(max); } return c.list(); } catch (final HibernateException ex) { TOBaseHibernateDao.logger.error(ex); throw convertHibernateAccessException(ex); } } protected void addOrderToCriteria(Criteria c) { } public boolean include(Object propertyValue, String propertyName, Type type) { if((propertyValue!=null) && (propertyValue instanceof String)){ return !"".equals(((String)propertyValue).trim()); } return propertyValue!=null; } }
onde o método addOrderToCriteria, permite que subclasses deste DAO ordenem as consultas …
o método addPropertiedToCriteria permite que subclasses adicionem propriedades não incluidas pelo hibernate nas consultas …
e o método include combinado com o setPropertySelector da classe Example é uma melhoria adicionada a pouco tempo, que faz o mesmo que o addPropertiedToCriteria, mas de forma automática, ou seja, inclui as propriedades PK e FK também na QBE …
…
Bom, depois disto tudo, só falta criar o DAO para alguma entidade persistida pelo Hibernate, como por exemplo uma classe Curriculo …
Criamos a interface do nosso DAO:
package br.com.techoffice.site.dao; import br.com.techoffice.site.data.Curriculo; public interface CurriculoDao extends TOBaseDao{ }
e logo depois a implementação deste DAO:
package br.com.techoffice.site.dao.impl; import net.java.dev.springannotation.annotation.Bean; import br.com.techoffice.site.dao.CurriculoDao; import br.com.techoffice.site.data.Curriculo; @Bean(name="curriculoDao") public class CurriculoDaoImpl extends TOBaseHibernateDaoimplements CurriculoDao { private static final long serialVersionUID = 1L; public CurriculoDaoImpl() { super(Curriculo.class); } }
acho que era isto, o que acharam deste DAO genérico?
pela minha experiência, ele resolve de maneira estupidamente fácil em torno de 60% dos meus problemas de persistencia, nos outros 40% ai é necessário criar algum outro metodo de pesquisa especializado para cada situação …
mas acho que é esta a ideia das coisas genéricas, facilitar a maior parte do trabalho e permitir que a menor parte seja feita com um pouquinho de trabalho extra
o que vocês acham?
Se você gostou deste post, lembre-se de assinar o RSS feed do blog, para ser notificado de novos posts!
Tags: Java
Bom dia Francisco,
No meu caso eu tenho um DAO genérico que contém apenas os métodos que são comuns a todas as entidades, o mesmo é abstrato.
Os demais daos herdam o dao genérico.
Porém por questões de manutenabilidade e também por utilizar o spring, o struts 2 e o hibernate (obs: acredito que nenhum dos frameworks obriga o uso de interface), todas as minhas daos possuem uma interface e nas Actions (Struts 2) eu delcaro as minhas instâncias com a Interface e o Spring se encarrega de criar a intância correspondente e injetá-lo na Action.
import scfc.model.dao.ChamadoDAO;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
public class ManterOrdemServico extends ActionSupport implements Preparable, SessionAware{
//interface
private ChamadoDAO chamadoDao;
//…
}
Desse modo, caso eu queira mudar a implementação do meu dao generico basta criar uma nova classe que implemente a interface da minha entidade e que herde a nova implementação da classe genérica. E no xml de configuração do spring, basta mudar a classe para a nova.
Isso facilita mto, pois esse tipo de alteração torna-se transparente para o restante do sistema.
public interface GenericDAO {
void save(T entity);
void update(T entity);
void remove(T entity);
T find(ID id);
List findAll();
T getReference(ID id);
}
@Transactional
public abstract class GenericImplDAO implements GenericDAO{
private Class persistentClass;
@PersistenceContext
private EntityManager em;
@SuppressWarnings(”unchecked”)
public GenericImplDAO(){
this.persistentClass = (Class)((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
public void setEm(EntityManager em) {
this.em = em;
}
protected EntityManager getEm() {
return em;
}
public Class getPersistentClass() {
return persistentClass;
}
@Override
public void save(T entity) {
em.persist(entity);
}
@Override
public void update(T entity){
em.merge(entity);
}
@Override
public void remove(T entity) {
em.remove(entity);
}
@Override
public T find(ID id) {
return em.find(getPersistentClass(), id);
}
@Override
public List findAll() {
return findByCriteria();
}
@SuppressWarnings(”unchecked”)
protected List findByCriteria(Criterion… criterion) {
Session session = (Session) em.getDelegate();
Criteria crit = session.createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
return crit.list();
}
@SuppressWarnings(”unchecked”)
protected List findByCriteria(Order o, Criterion… criterion) {
Session session = (Session) em.getDelegate();
Criteria crit = session.createCriteria(getPersistentClass());
for (Criterion c : criterion) {
crit.add(c);
}
crit.addOrder(o);
return crit.list();
}
@Override
public T getReference(ID id) {
return getEm().getReference(getPersistentClass(), id);
}
}
public interface ServicoDAO extends GenericDAO {
List findAllForContrato(Categoria cat);
}
public class ServicoImplDAO extends GenericImplDAO implements ServicoDAO {
@Override
public List findAllForContrato(Categoria categoria) {
Conjunction c = Restrictions.conjunction();
c.add(Expression.eq(”contrato”, true));
c.add(Expression.eq(”categoria”, categoria));
return findByCriteria(c);
}
}
Espero ter ajudado.
Raphael, você poderia dar mais detalhes da sua integração entre Struts2 + Spring + Hibernate(JPA) ao qual se referiu no seu post? Poderia postar o applicationContext?
orbigado,
Leonardo
Exemplo de um applicationContext.xml.
<!– Alternativa caso queira configurar a conexão com o banco direto da aplicação
–>
Na documentação do Spring mostra outras alternativas para algumas configurações.
No site do Struts 2 (versão 0) tem um exemplo de intregralção entre eles, há também um exemplo de integração no site da revista java magazine.
Mas se sugirem dúvidas posta ai.
Ops…
deu algum erro na hora de postar.
segue novamente o applicationContext.xml.
<!– Alternativa caso queira configurar a conexão com o banco direto da aplicação
–>
Troquei o símbolo de comentário do xml por //, vamos ver se agora vai.
// Usa o JNDI configurado no Container
// Alternativa caso queira configurar a conexão com o banco direto da aplicação
//
//
//
//
//
//
// Atentar-se para a propriedade database, ela corresponder ao seu banco.
// Veja na documentação do spring qual o valor que você deve colocar.
//
Muito obrigado ajudou sim, e esclareceu bastante dúvidas…vlw cara.
Olá urubatan, esse tutorial foi feito em dezembro de 2006. Até hoje tenho procurado alguma coisa mas recente sobre isso e não tenho encontrado. O que estou querendo é exatamente as configurações do hibernate no meu applicationContext mas só enconto artigos antigos. Tem algo mais recente que possa me indicar?
Grato!
Anderson,
Quanto as configurações do hibernate no applicationContext, você pode criar um datasource no context.xml e pegar a conexão via jndi no applicationContext
Olá Gessé,
Algumas coisas ainda são meio obscuras para mim, mas nada que não possa ser resolvido. Já estou quase conseguindo, de qualquer forma agradeço pela força.
Ok Anderson…
Qualquer coisa é só perguntar…
deu erro denovo.
<!– Alternativa caso queira configurar a conexão com o banco direto da aplicação
–>
Cara como fica isso no spring ? O genericDao tem que ter alguma configuracao especifica ?
valeu
O genericDao não, mas o hibernate sim.
No momento ainda não consegui configurar no spring, mas estou utilizando uma classe utilitaria temporaria e espero jogar isso pro spring em breve.