[quote=AdemirPinto]Pessoal,
segui alguns conselhos do pessoal e melhorei bem meu Generic DAO(parte do código abaixo)…muito obrigado a todos.
Só que ainda falta alguns detalhes e dentre eles a questão da Sessão e Transação. Com relação à sessão eu fiz um filter para criar ele e depois em cada requisição eu a recupero, conforme o código abaixo. As dúvidas ainda são:
1)Vocês acham que ficou bom meu HibernateSessionRequestFilter?
2)Estava pensando em fazer o controle de transação nos meus Managed Bean, o que voces acham?
3)No site http://community.jboss.org/wiki/OpenSessioninView tem uma implementação com o controle de transação no filter, isso não é complicado? Tipo eu quero fazer um controle melhorar das minhas exceções para tratar a saida para o usuario. Outra coisa é que ele fica dando beginTransaction e depois commit, mas pode acontecer que a requisição não alterou o banco de dados. O que vocês acham dessa implementação? Vale a pena fazer o controle de transação assim?
HibernateSessionRequestFilter:[code]
public class HibernateSessionRequestFilter implements Filter {
private SessionFactory sf;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (Throwable ex) {
ex.printStackTrace();
throw new ServletException(ex);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Initializing filter...");
System.out.println("Obtaining SessionFactory from static HibernateUtil singleton");
sf = HibernateUtil.getInstace().getSessionFactory();
sf.openSession();
}
public void destroy() {
}
}
[/code]
HibernateUtil:[code]
public class HibernateUtil {
private static HibernateUtil me;
private SessionFactory sessionFactory;
public HibernateUtil() {
sessionFactory = new Configuration().configure().buildSessionFactory();
}
public Session getSession() {
Session toReturn = sessionFactory.openSession();
return toReturn;
}
public static HibernateUtil getInstace() {
if (me == null) {
me = new HibernateUtil();
}
return me;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
[/code]
GenericDAO:[code]
@SuppressWarnings(“unchecked”)
public class GenericDAO {
@SuppressWarnings("rawtypes")
private Class persistentClass;
private Session session;
//Construtor - ##########################################
@SuppressWarnings("rawtypes")
protected GenericDAO(Class p_persistentClass) {
session = HibernateUtil.getInstace().getSession();
persistentClass = p_persistentClass;
}
public Session getSession() {
return session;
}
@SuppressWarnings("rawtypes")
public Class getPersistentClassLocal(){
return persistentClass;
}
public void insert(T obj) throws Exception {
session.save(obj);
session.flush();
}
public void update(T obj) throws Exception {
session.update(obj);
session.flush();
}
public void delete(T obj) throws Exception {
session.delete(obj);
session.flush();
}
public Integer count(List<Criterion> criterion) throws Exception {
Criteria criteria = session.createCriteria(persistentClass);
for (Criterion c: criterion)
criteria.add(c);
criteria.setProjection(Projections.rowCount());
return ((Integer) criteria.uniqueResult()).intValue();
}
//Lista todos os registros com ordem e sem limite
public List<T> listAll(String fieldOrder, SortOrder sortOrder) throws Exception {
String ord = ConstantesGerais.TIPOORDEMASC;
if (sortOrder == SortOrder.DESCENDING)
ord = ConstantesGerais.TIPOORDEMDESC;
Criteria criteria = session.createCriteria(persistentClass);
addOrder(criteria, fieldOrder, ord);
return criteria.list();
}
…
[/code]
Abraços a todos e um bom FDS.
Ademir[/quote]
o melhor mesmo é você usar algum framework para gerenciar isso, como o spring que nosso amigo citou… eu ja testei uns negocios legais semelhantes a isso com EJB também, o “HibernateUtils” passa a ser desnecessário (ele injeta o seu “gerenciador de conexões” que é semelhante a session do hibernate, da o commit ou rollback automatico… enfim), mas supondo que você não vá usar isso, algumas dicas:
No hibernateUtils, normalmente se diexa o construtor dele privado, para que ninguém consiga instanciar essa classe, para se obter instancias dele deve-se usar um método public static getInstance, para então a partir deste se obter a sessão pelo getSession, ou então nem criar o getInstance, deixando o getSession estatico também para ser acessivel de fora do objeto (eu gosto de fazer dessa forma ja que este é o unico método que deixo acessivel nessa classe). Não deixo getters e setters do seu SessionFactory, classes de fora não deveriam acessa-lo, apenas a própria classe de dentro para criar sessões, se você tiver deixado o getSession estático, você deixaria também o sessionFactory estático inicializaria ele em um bloco também estatico.
Veja esse exemplo, estou sem ide, podem ter erros de digitação e por isso não compilar:
[code]public class HibernateUtil {
private static HibernateUtil me;
private static SessionFactory sessionFactory;
static {
sessionFactory = new Configuration().configure().buildSessionFactory();
}
public static Session getSession() {
Session toReturn = sessionFactory.openSession();
return toReturn;
}
}[/code]
o formato do padrão singleton normalmente é aquele que expliquei, construtor privado, uma instancia de si própria usado no getInstance (do jeito que você estava usando), e ai o getSession, seria o mesmo que você estava fazendo sem permitir acesso ao sessionFactory e com o construtor privado, mas acho que desse jeito é melhor, não precisa ficar chamando getInstance e não tem por que trabalhar com objetos neste caso.
O seu filter também não está 100 %, repare que sua sessão nunca é fechada, nem disponibilizada de alguma forma para o modelo, desse jeito não sei como você obteria ela no seu modelo, vocÊ ainda precisaria chamar o hibernateUtils la, sendo que esse filtro é justamente para vocÊ não fazer isso, veja o exemplo abaixo:
ps. editei por que vi que do jeito que estava a sessão ficaria fora de escopo na hora de fechar…
[code]public class HibernateSessionRequestFilter implements Filter {
public static String HIBERNATE_SESSION_NAME = "sessao_hibernate";
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Session s = null;
try {
//prefira usar algum log de verdade para isso
System.out.println("Obtaining SessionFactory from static HibernateUtil singleton");
s = HibernateUtil.getSession();
HttpSession httpSession = ((HttpServletRequest) request).getSession(true);
httpSession.setAttribute(HIBERNATE_SESSION_NAME, s);
chain.doFilter(request, response);
} catch (Throwable ex) {
ex.printStackTrace();
throw new ServletException(ex);
}
try {
if (s != null) s.close();
} catch (Throwable ex) {
//logar aqui
ex.printStackTrace();
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
} [/code]
assim no seu modelo você pegaria sua sessão e obteria a sessão do hibenrate na sessão pelo nome chapado na constante existente no filtro.
a, mesmo que vocÊ use algum framework, é interessante você entender este conceito…
editando denovo… agora que eu vi seu item 2… se você colocar o gerenciamento das transações no controller, ai o seu modelo fica ± dependente dele. O ideal é você desacoplar ao máximo as camadas… vamos a um exemplo: se o seu cliente quiser portar a aplicação que está sendo feita de web para destop por exemplo, como você está desenvolvendo em camadas e tem uma camada de modelo na aplicação web, pode pode colocar essa camada interinha na aplicação desktop certo? ai no controller da sua aplicação desktop você só chama o modelo e ele ja faz tudo o que tem que fazer… estranhamente o modelo para inserir clientes (exemplo) não loga nenhum erro, a aplicação fala que cadastrou com sucesso mas o dado não ta la na base… depois de muito analisar o código você vê que não commitou, isso por que o commit ou rollback ficaria no controller, você não copiou o controller e esqueceu de re-escrever isso na app desktop. Ja descobrimos ai dois problemas, o primeiro é que uma camada tem certa dependencia da camada acima, o que não é o ideal, o segundo problema é que você está re-escrevendo código. Se você tivesse colocado isso no modelo la certiho, não teria nenhum destes problemas. Sim dessa forma leva um pouco mais de tempo e da um pouco mais de trabalho… no desenvolvimento do software, mas com certeza você terá menos trabalho e gastará menos tempo na manutenção (seja por correções, seja por alterações), e acredite, o normal é gastar mais tempo na manutenção de um software do que na construção…
a se la para frente alguém decidir alterar o framework mvc você terá os mesmos problemas que no exemplo que eu citei.
nessa thread, que é de outro assunto mais ai o assunto mudou para “colocar o modelo no managed bean do jsf”, eu tentei explicar resumidamente o por que de isso ser uma ideia ruim…