Blog do Urubatan
msgbartop
Desenvolvedor, Arquiteto, Palestrante, Coordenador do RSJUG, Patinador e Blogger
msgbarbottom

27 Dec 06 DAO Generico - um exemplo a pedidos

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 TOBaseHibernateDao extends 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 TOBaseHibernateDao implements 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:

Reader's Comments

  1. |

    PERFEITO ESSE DAO!

    Urubatan muito bom post. Muito bem explicado!!!

    Parabens amigo!!!

    Reply to this comment
  2. |

    Urubatan eu tinha visto este seu DAO num workshop no webdays, ficou muito bom mesmo …..

    Reply to this comment
  3. |

    Parabéns pelo trabalho que vem realizando pela comunidade, há algum tempo acompanho, então resolvi deixar meu recado…

    Reply to this comment
  4. |

    Opa Uburatan ta show esse dao genérico, parabéns.

    Tenho umas duvidas simples.

    esse Propagation.REQUIRED está dizendo que a transação é obrigatória para todos os métodos? aquele mesmo esquema quando declarado via xml?

    E a respeito do include ai, você explicou mas eu fiquei viajando, poderia explicar de outra forma ou passar algum link?

    Como você está utilizando o HibernateDaoSuport, teria alguma vantagem se utilizasse o método getHibernateTemplate() e/ou utilizar aquele esquema da interfacer HibernateCallback ?

    Uma correção besta é que no método get está utilizando load ou invés de get.

    Reply to this comment
  5. |

    Valeus Gécen :D
    Thiago,
    o Propagation.REQUIRED é do spring, e sim, quando ele esta anotando uma classe diz que todos os metodos requerem uma transação …

    quanto ao include, o esquema é que o QueryByExample do Hibernate não inclui campos de relacionamento e PKs, aquele include é chamado quando eu chamo
    [java]
    Example.create(example).enableLike(MatchMode.ANYWHERE).ignoreCase().setPropertySelector(this)
    [/java]

    ou seja, é o callback do property selector do hibernate apenas …

    e quanto a HibernateTemplate X convertHibernateAccessException(ex);
    uso a segunda opção por que acho mais bonito só, mas não vejo nenhuma razão concreta para usar uma ou a outra abordagem …
    :D

    Reply to this comment
  6. |

    Olá Urubatan, entendi agora, vlw.

    Só mais uma duvida.
    E a respeito do objectClass que é passado como construtor das classes concretas, ele é realmente preciso já que estamos passando o tipo via generics? eu vi no blog da caleum um artificio que não precisaria dessa classe, conforme no link abaixo:

    http://blog.caelum.com.br/2006/10/29/brincando-com-generics-o-bizarregenericdao/
    o que você acha dessa solução?

    Reply to this comment
  7. |

    Eu tb escrevi um pouco sobre a classe que é passada no construtor (ou melhor, sobre a ‘mágica’ necessária pra eliminá-lo): http://javapub.blogspot.com/2006/12/generics-reflection-hierarquias-de.html

    No fim, eu achei melhor manter essa passagem por parâmetro do que me aventurar nessa zona obscura :)

    Reply to this comment
  8. |

    Oi,

    O dao ficou muito bom. Gostaria de saber se você não acha mais interessante algo como “return listAll().size()” no lugar de instanciar um Integer nos métodos de page count?

    Abraços

    Reply to this comment
  9. |

    realmente seria melhor …
    não lembro por que esta implementado desta forma, deve ter ficado assim em alguma das metamorfoses sofridas por este DAO durante o tempo de vida dele e eu não prestei atenção :S

    Vaoeu a dica :D

    Reply to this comment
  10. |

    Legal, muito boa implementação, existiria alguma forma de injetar o objectClass pelo Spring?

    Reply to this comment
  11. |

    Urubatan, por curiosidade, porque você chama o flush() após o save() e update()?

    Reply to this comment
  12. |

    sim, é possivel injetar o objectClass pelo spring …

    e diego, eu realmente não lembro o por que do flush, acho que no projeto em que eu fiz isto, estava dando algum bug de batch update e eu tentei resolver assim antes de desabilitar o batch update do hibernate …

    Reply to this comment
  13. |

    Muito bom o DAO
    So uma duvida… nao seria melhor ter uma classe de negocio e colocar a anotacao dizendo que é requirido uma trasacao nela
    por exemplo:

    @Transactional(propagation = Propagation.REQUIRED, timeout = 20)
    public class ContaCorrente(){
    public retirar(){
    ContaDAO conta = factory.getContaDAO();
    UsuarioDAO usuario = factory.getUsuarioDAO();

    }
    }

    assim todos os DAOs estariam dentro de uma mesma transacao… eu faco uma implementacao assim

    Reply to this comment
  14. |

    A vantagem desta abordagem é que a configuração mais externa é a que vale.
    por exemplo, estou dizendo que os metodos do DAO requerem uma transação, isto não quer dizer uma transação nova …
    por tanto, se no business, o metodo necessitar de uma transação, sera criada uma transação para aquele metodo, e todas as chamadas de dao de dentro daquele metodo utilizarão a mesma transação, por tanto, todas as chamadas estarão dentro da mesma transação …
    assim a transação sera maior, e ainda assim atomica.

    mas caso o metodo do business não precisar de uma transação, serão criadas pequenas transações para cada chamada a um metodo de um DAO.

    ou seja, fica valendo a maior transação :D

    Reply to this comment
  15. |

    Olá Urubatan, primeiramente parabéns pelo trabalho, tenho uma dúvida sobre transação.
    Por exemplo em uma transação em que eu tenha q inserir dados de uma nova venda e dados de itens dessa venda, essa implementação do Dao genérico contempla esse tipo de situação ou tenho que fazer isso por fora.

    inicio da transacao

    daoVenda.salvar(venda);
    daoItens.salvar(itens);

    fim da transacao

    algo onde a transação deveria ser mais ou menos assim, um exemplo tosco só para ter um idéia.

    Mais uma vez parabéns pela iniciativa.

    Reply to this comment
  16. |

    Mário, da uma olhada no meu comentário anterior que explica exatamente isto …

    Reply to this comment
  17. |

    Beleza, pensei que com objetos de dao’s diferentes ele fazia diferentes transacoes.
    Valeu.

    Reply to this comment
  18. |

    Ola

    Copiando o que vc escreveu:
    A vantagem desta abordagem é que a configuração mais externa é a que vale.
    por exemplo, estou dizendo que os metodos do DAO requerem uma transação, isto não quer dizer uma transação nova

    Gostaria de saber como vc fez para trabalhar com essa abordagem, o seu artigo explica detalhes de como funciona o DAO generic, que por sinal é muito bom, mas nao explica como fazer o controle de transação. Vc tem algum material explicando como fazer ?

    Obrigado.

    Reply to this comment
  19. |

    Ronildo, desculpe a demora na resposta, não tinha visto a pergunta …
    o controle de transações funciona exatamente como em um session bean com CMT, ou seja, vale a transação de maior escopo …
    demarcação para a classe vale para todos os métodos
    demarcação no método sobre escreve a da classe

    e se tem todas as opções de propagação de transações que existem nos EJBs.
    mais informações sobre isto na documentação dos EJBs ou na documentação do spring :D

    Reply to this comment
  20. |

    Urubatan, gostei da sua implementação do TOBaseHibernateDao e passei a utilizar algo bem semelhante como base para meus Daos.

    Utilizo também uma factory para os Daos, mas estou com um problema com as transações:

    Erro: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

    Pesquisei bastante sobre isso, mas não encontrei uma solução. Consigo fazer com o funcione se chamar getSession(true), isto é, permitindo que uma transação seja criada nesse momento, o que não é recomendado, pelo que li.

    Como você configura seu applicationContext para usar essa implementação?

    Outra dúvida, relativa à pergunta do Mário Dantas: como eu consigo começar e finalizar uma transação “por fora” dos Daos, já que eles não expõe os métodos relativos à session?

    Reply to this comment
  21. |

    Dê uma conferida aqui Lucas.

    http://pastebin.co.uk/13149

    Reply to this comment
  22. |

    Valeu Thiago! Havia encontrado algo semelhante aqui uns minutos antes de você postar e me deparei com outro erro. Usei o que você postou (achei melhor do que o que eu havia encontrado, pois especifica mais níveis de isolamento).

    Porém, agora estou com outro erro…

    Faço um listAll() numa classe Cliente. Essa classe possui uma Collection com lazy loading. Para buscar os clientes dá tudo certo. Porém, quando tento iterar pela coleção de pedidos:


    Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.lecom.tecnologia.model.Cliente.pedidos, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
    at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    at com.lecom.tecnologia.main.Tester.test(Tester.java:29)
    at com.lecom.tecnologia.main.Main.main(Main.java:17)

    Pelo jeito a sessão está sendo “perdida”. O logger me retorna algumas coisas relacionadas a isso (após selecionar os clientes com sucesso):


    DEBUG [main] (TransactionAspectSupport.java:305) - Completing transaction for [com.lecom.tecnologia.dao.IGenericDao.listAll]
    DEBUG [main] (AbstractPlatformTransactionManager.java:819) - Triggering beforeCommit synchronization
    DEBUG [main] (AbstractPlatformTransactionManager.java:832) - Triggering beforeCompletion synchronization
    DEBUG [main] (TransactionSynchronizationManager.java:190) - Removed value [org.springframework.orm.hibernate3.SessionHolder@3b4b1e] for key [org.hibernate.impl.SessionFactoryImpl@c0a9f9] from thread [main]
    DEBUG [main] (AbstractPlatformTransactionManager.java:845) - Triggering afterCommit synchronization
    DEBUG [main] (AbstractPlatformTransactionManager.java:861) - Triggering afterCompletion synchronization
    DEBUG [main] (SessionFactoryUtils.java:781) - Closing Hibernate Session
    DEBUG [main] (TransactionSynchronizationManager.java:272) - Clearing transaction synchronization

    Alguma idéia?

    Reply to this comment
  23. |

    Ai nesse caso, você tem que carregar a coleção de pedidos antecipadamente, pois quando você tenta acessa-la a sessão já foi fechada por isso da o lazy.

    Vai lá na documentação do hibernate e procura sobre fetch, você pode setar no seu mapeamento como default para sempre carregar a coleção, ou no metodo que estiver realizando a query, via criteria ou hql, especificar se deve carregar ou não.

    Reply to this comment
  24. |

    Pois é, nas buscas que eu fiz encontrei isso mesmo. Ele fecha a sessão após cada transação, então ao tentar pegar a lista de pedidos vai dar erro pois já é outra sessão…

    A minha dúvida é: por esse motivo perco o benefício de desempenho que ganho com o lazy loading? Não há outro jeito a não ser fazer a query novamente utilizando left join fetch?

    Reply to this comment
  25. |

    ùma solução para isto é se você estiver utilizando Hibernate sem o spring (o que parece por causa da factory que você mencionou) mudar na configuracão do hibernate para managed sessions, assim você cria e destroi as sessions.
    caso esteja utilizando o spring utilize algo parecido com isto:
    [java]
    SessionHolder sessionHolder =
    (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
    if(sessionHolder==null){
    TransactionSynchronizationManager.bindResource(getSessionFactory(),new SessionHolder(getSessionFactory().openSession());
    }[/java]

    não se esqueça que fazendo isto você é o responsável por fechar a sessão também …

    Reply to this comment
  26. |

    PS.: eu achei muito legal outro visitante do blog responder uma duvida em um comentário :D Muito obrigado Thiago.

    Reply to this comment
  27. |

    Muito legal a inciativa do Thiago mesmo.

    Urubatan, estou usando o Spring sim. É uma prática ruim usar uma DaoFactory com Spring?

    Não tenho o código agora, está no trabalho, mas fiz mais ou menos o seguinte:

    Uma interface genérica, semelhante a sua TOBaseDao.
    Uma classe abstrata com a implementação dessa interface para o hibernate, como a classe TOBaseHibernateDao.
    Uma interface genérica para a DaoFactory, com métodos como: public IClienteDao getClienteDao;
    Uma interface e implementação para cada Dao, onde posso colocar métodos específicos.

    A implementação da factory possui os atributos (as interfaces dos Daos) que são injetadas via método set pelo Spring.

    Nas classes que consomem os Daos, tenho apenas a interface da factory como atributo e a implementação é injetada pelo Spring.

    Obrigado pelo retorno, vou tentar isso no trabalho amanhã (trabalho da faculdade hoje =/ ).

    Sobre a minha segunda pergunta no primeiro post, alguma orientação? A mais óbvia que vejo seria colocar dentro de um Dao chamadas a outros, fazendo tudo na transação do primeiro, mas acho que isso não é muito bom…

    Reply to this comment
  28. |

    Como não quero ter que controlar a sessão, fiz o seguinte: antes de acessar a coleção de pedidos, uso o método clienteDao.rebind(cliente). Agora ele usa uma transação para buscar os clientes e depois uma transação para buscar cada lista de pedidos. Funciona, mas achei bem feio…

    De acordo com o que pesquisei, o padrão OpenSessionInView resolve isso, está correto?

    Reply to this comment
  29. |

    esta solução do rebind funciona também :D mas prende o teu código a api do Hibernate se isto não estiver sendo feito dentro de um DAO.
    se bem que não é exatamente um problema prender o código a API do Hibernate :D
    PS.: o OpenSessionInView também resolve isto …

    Reply to this comment
  30. |

    Urubatan, como você costuma contornar essa situação? Ou você não utiliza lazy loading?

    Reply to this comment
  31. |

    Opa, vlw pessoal.

    Eu não custumo utilizar muito lazy loading, pelo menos no projeto no qual estou envolvido.
    Como utilizo ajax, via DWR, quando realizo as consultas geralmente trago tudo que eu quero, como o sistema não lida com grande volume de dados creio que não tem problemas, fora que realizo paginações para trazer uma quantidade limitada de dados.

    Reply to this comment
  32. |

    Lucas, eu uso lazy bastante e como a maior parte das apps é web, o OpenSessionInView ja resolve o meu problema …
    quando trabalho com ajax procuro não utilizar as mesmas entidades (hoje estou fazendo isto e estou transformando em HashMaps os valores transferidos via ajax.

    e quando o OpenSessionInView não resolve, como esta semana que tive que implementar um wizard com a sessão aberta durante todo o wizard, eu copiei o OpenSessionInView filter do Spring, e fiz com que quando eu estivesse no wizard, ele armazenasse a session na HttpSession e usando um código parecido com:
    [java]
    SessionHolder sessionHolder =

    (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());

    if(sessionHolder==null){

    TransactionSynchronizationManager.bindResource(getSessionFactory(),new SessionHolder(getSessionFactory().openSession());

    }

    [/java]
    ele enquanto ainda no wizard, recuperasse a sessão do HttpSession e utilizasse a mesma durante todo o wizard :D
    mas como sempre, a solução mais apropriada, depende de cada situação :D

    Reply to this comment
  33. |

    Legal… por enquanto estou apenas testando o Spring com Hibernate, então estou escrevendo uma aplicação console mesmo. Esse “esquema” do SessionHolder funcionou bem, apenas adicionei o “unbinding” antes de finalizar a aplicação:


    TransactionSynchronizationManager.unbindResource(this.sessionFactory);
    SessionFactoryUtils.releaseSession(session, this.sessionFactory);

    Estou fazendo uma aplicação também em .NET com NHibernate e lá costumo colocar a session no HttpSession também… funciona =D

    Alguma opinião sobre a minha implementação com factory? Estive pensando: seria bom eu configurar os beans dos Daos como lazy-init? Acho que seria uma boa, já que na factory eu tenho a injeção de todos os Daos, mas não vou utilizar todos sempre.

    Reply to this comment
  34. |

    bom, sobre a factory …
    containers IoC foram criados para que ninguem mais utilizasse factories …
    por tanto, ou tu utiliza o spring ou a tua dao factory, não as duas coisas junto …

    mas esta é só a minha opinião :D

    Reply to this comment
  35. |

    Sim, faz sentido… na verdade essa factory não tá criando nada, ela apenas retorna os daos que são injetados, então ela acaba perdendo a semântica de criadora, passando a ser apenas um objeto agregador, ou seja, acaba não sendo uma factory de verdade.

    Vi muita gente usando Spring e Castle Windsor (container IoC pra .NET) com essa “factory”, então acabei fazendo da mesma forma. Vou procurar saber mais sobre isso.

    Obrigado pela ajuda! :D

    Reply to this comment
  36. |

    Olá Urubatan,

    Primeio gostaria de parabenizar pelo DAO genérico que vc construi. Desenvolvi um dao bem parecido com esse aí, só que o único problema aí é que tenho que criar uma classe dao concreta para todas as minhas classes persistíveis.

    Há alguma forma de isso não ser necessário?

    Reply to this comment
  37. |

    é só alterar ele para passar o objectClass como parametro para o método que precisar dele :D

    Reply to this comment
  38. |

    Olá,

    Muito bom seu artigo!!

    So fiquei com uma dúvida:

    E se eu quisesse que uma classe CurriculoDireito que estende Curriculo tivesse também um DAO que extendesse o DAO de Curriculo, como proceder?

    public interface CurriculoDAO extends TOBaseDao{
    public List getCurriculosByName();
    }

    Estou batendo a cabeça aqui mas não acho solução.

    public interface CurriculoDireitoDAO extends CurriculoDAO {
    // este deve ser implicito
    // public List getCurriculosByName();
    public List getCurriculoEstruturaDireito();
    }

    é uma sugestão meio tosca, mas o que eu gostaria era de poder Herdar os metodos das interfaces dos DAOs..

    Postei uma dúvida sobre isso no GUJ, e me direcionaram para seu blog :)
    http://www.guj.com.br/posts/list/66036.java

    se você tiver alguma idéia, seria muito grato.

    vlw

    Abraços e parabéns!

    Reply to this comment
  39. |

    não entendi a dúvida …
    este DAO genérico não atrabalha em nada a utilização de herança …

    Reply to this comment
  40. |

    para dar um exemplo de um blog

    Reply to this comment
  41. |

    Urubatan, poderia me explicar como funciona exatamente este método…
    public List findByExample(final T example, final int first, final int max)

    Reply to this comment
  42. |

    Urubatan…
    esse “T” quer dizer o que mesmo ?que é um tipo indefinido ?

    Reply to this comment
  43. |

    alexandre, isto é a sintaxe de generics do Java 5 :D

    Reply to this comment
  44. |

    ola urubatan.
    sobre sua primeira classe TOBaseDao
    certez

    Reply to this comment
  45. |

    ola urubatan.
    sobre sua primeira classe TOBaseDao
    bom, como ela implementa classe Generic sem receber o parametro

    TOBaseDao

    essa e minha duvida !
    abs.

    Reply to this comment
  46. |

    Algum exemplo sem utilizar spring? com struts 2

    Reply to this comment
  47. |

    Achei bem legal essa classe, muito útil também.
    Sobre os métodos para contar regitros, fico meio preocupado, pois caso a tabela seja muito grande, todos os registros serão carregados?
    Não teria como fazer uma verificação só da qtde, como faríamos com o SQL (select count(*) from tabela)?

    Valeu

    Reply to this comment
  48. |

    Meio tarde mas se ajudar ainda:
    Fabio em uma entidade se vc mapear ela com
    @LazyCollection(LazyCollectionOption.EXTRA)
    O hibernate fica mais esperto no carregamento lazy, se vc der somente um size(), ele ira dar um count, tambem fica mais esperto quanto ao contains, verifica pelo banco em vez de carregar a lista e verificar em memoria.

    Reply to this comment
  49. |

    Olá Urubatan,

    Eu utilizo hibernate(jpa) com um dao genérico e funciona perfeitamente, exceto quando tento inserir uma entidade que herda outra entindade abstrata.

    Eu uso apenas um dao para todas as entidades filhas e por padrão o dao recebe o .class da entidade pai. Isto funciona perfeitamente para consultas polimórficas, porém ao inserir as classes filhas apenas os atributos herdados são persistidos.

    É possível fazer uma inserção “polimórfica” através do dao da entidade pai?

    Reply to this comment

Leave a Comment