Software, Java & afins

Fabricio Braga, Sun Certified

Utilizando NamedQueries em EJB 3.0

escrito por Fabricio Braga em Feb 2006

Os desenvolvedores que já utilizaram alguma vez o quarteto EJB 2.1 + Ant + XDoclet + SessionFacade certamente, ao terem contato com EJB 3.0 perceberão que algumas coisas mudaram também no nível do uso de padrões.

Eu por exemplo, utilizava o DTO, com um SessionFacade e gerava meus métodos finders todos no XDoclet. Procedimento que para mim era muito tranquilo, e eu achava razoavelmente fácil de implementar.

Se você não faz idéia do que estou falando, vou dar um breve explicação…

A Pattern SessionFacade é uma Pattern que tem como objetivo básico ocultar os detalhes da sua camada de persistência e simplificar seus métodos de negócio. Então na prática o cliente do seu EJB vai acessar sempre um método “facade” de um SessionBean, nunca um EntityBean ou um método que tenha alguma inteligência de negócio.

O XDoclet é uma ferramenta extensível e bastante poderosa, que tem como objetivo básico automatizar processos como geração de código baseada em templates, geração de arquivos descriptors para containers, dentre outras coisas.

O DTO (ou DO) é uma Pattern utilizada, neste caso, para facilitar a troca de informações entre os objetos de negócio, diminuir a quantidade de chamadas ao método e consequentemente o overhead na rede.

Em geral, eu fazia rapidamente um novo componente de negócio, simplesmente escrevendo os meus métodos “finder” nas tags do XDoclet, dentro do Entity e já adicionando tags específicas para o descriptor do container, que nesse caso era o JBoss.

Na especificação EJB 3.0 o Entity não é mais um Business Object, mas um POJO, então não precisamos por exemplo, utilizar mais a Pattern DTO. E como agora temos o recurso das “Annotations“, não precisamos mais do XDoclet para gerar nossas interfaces Local e Remote.

Sendo assim, o papel antes feito pelo DTO é feito agora pelo próprio EntityBean, e o que o XDoclet fazia gerando os métodos “finders” automaticamente no descriptor, é feito agora pelas “NamedQueries”. Tema deste artigo.

Onde escrevemos nossas queries EJB QL agora (a partir da especificação 3)? Em métodos finders do SessionFacade?

Imagine um cenário onde você tenha uma entidade “Usuario” e queira fazer objetos de negócio para ele. É razoável pensarmos que temos algo assim:


import javax.persistence.Entity;
import javax.persistence.Table
@Entity
@Table (name="USUARIO")
public class Usuario implements java.io.Serializable{
private String nome;
private String senha;
...
}

Agora o SessionBean para ele, como o método finder que faria a nossa consulta:


@Stateless
public class UsuarioServiceBean {

public Usuario findByNomeSenha(String nome, Stirng senha) throws RemoteException{
//aqui uma provável consulta, com código EJB QL
String ejbQl = "from Usuario u where u.nome =:nome, u.senha =:senha";
Usuario result = (Usuario)entitManager.createQuery(ejbQl).setParameter("nome", nome).
setParameter("senha", senha).getSingleResult();
return result;
}
}

Esta seria provavelmente a abordagem utilizada pela maioria das pessoas e inclusive é utilizada no próprio tutorial do site do JBoss. Mas seguindo a logica da pattern SessionFacade, seria razoável termos no próprio Entity os finders relacionados a ele.

Vejamos então uma abordagem mais limpa e mais adequada ao pattern, começamos com o nosso Entity:


import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

@Entity
@Table(name="USUARIO")
@NamedQueries({
@NamedQuery(name="findByNomeSenha",
query="from Usuario u where u.nome =:nome, u.senha =:senha")
})
public class Usuario imlements java.io.Serializable{
//aqui nada muda, o código permanece igual
...
}

Perceba que agora nosso método finder foi colocado dentro da Annotation e pertence ? classe Usuario. No método Facade do nosso Session, faríamos agora o seguinte:


public Usuario findByNomeSenha(String nome, Stirng senha) throws RemoteException{
Query query = entityManager.createNamedQuery("findByNomeSenha");
query.setParameter("nome", nome);
query.setParameter("senha", senha);
return (Usuario)query.getSingleResult();
}
}

A principal motivação para utilizar esta abordagem é que concentramos no nosso Entity (no caso, a classe Usuario) todas as queries que sejam relacionadas a ele. Imagine por exemplo que o nosso Facade UsuarioServiceBean não fizesse apenas consultas relacionadas ao Entity “Usuario”, mas também a “Perfil” e “Acesso”.

Então teríamos no Facade código EJB QL relacionado a diferentes Entitys, o que não é muito razoável em termos de manutenção e foge da idéia de usar um “Facade”.

Incrivelmente não há muitos sites recomendando explicitamente esta forma de desenvolvimento, como eu mencionei, e até mesmo no tutorial do JBoss não é utilizada esta implementação. Entretanto ela é a que melhor se adequa ao uso da Pattern SessionFacade.

Fabricio Braga

  1. Rodrigo Said,

    Perfeito!
    Era exatamente esse tipo de artigo que eu estava procurando. Estou vindo de uma abordagem com DAOs partindo para EJB3. Me pareceu um bocado estranho colocar métodos finders na Facade, justamente por estar reunindo operações de entitys diferentes. Me pareceu confuso. Procurei por exemplos ou por discussões a respeito, mas não encontrei nada.
    Esas abordagem, utilizando NamedQueries no entity, me parece muito mais razoável, mas queria encontrar alguém que concordasse comigo antes de baixar a cabeça sobre o código!
    Bom trabalho!

  2. Pedro Furlanetto Said,

    Não sei se o JPA tem, mas o hibernate tem e não consegui usar: NamedNativeQuery… já tentou?

  3. Fabricio Braga Said,

    Já usei sim, não é muito trivial. Usei isso com a especificação ainda na versão beta, mais ou menos na época em que escrevi esse artigo.

    Lembro que funcionou na boa e minha motivação havia sido alguma limitação das named queries para o MySQL, na realidade alguma limitação do EJBQL.