Hibernate – Utilizando a api Criteria
Esse post faz parte de uma série que estou preparando sobre o hibernate, o primeiro foi sobre a extensão especial Hibernate Spatial e esse segundo irei falar sobre um pouco sobre um poderoso recurso do Hibernate, a API Criteria. Nesse tutorial não irei entrar em detalhes sobre configuração do Hibernate, assume-se que você tem o hibernate pré-configurado, irei apenas falar da API.
Primeiro criaremos nossa entidade exemplo “Cliente” :
package modelo;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
*
* @author lucas
*/
@Entity
public class Cliente implements Serializable {
@Id
@GeneratedValue
private int id;
private String nome;
private int idade;
private String cpf;
private double saldo;
public String getCpf() {
return cpf;
}
public int getIdade() {
return idade;
}
public void setIdade(int idade) {
this.idade = idade;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public double getSaldo() {
return saldo;
}
public void setSaldo(double saldo) {
this.saldo = saldo;
}
}
Até aqui nada de novo, marcamos a classe com a anotação @Entity, para indicar que é uma entidade e marcamos o atributo id com as anotações @Id e @GeneratedValue, a primeira diz que esse atributo é a chave primaria e segunda que seu valor será gerado automaticamente. O cliente também tem um atributo saldo, que representará um valor de saldo, tecnicamente o cliente não deveria possuir um saldo e sim um objeto conta e a conta possuir um saldo, porém como o objetivo desse tutorial é demonstrar a api Criteria, não me apeguei a regras de modelagem OO.
Agora criaremos a classe HibernateUtil, que irá conter um método estático que devolve um objeto Session. Com essa classe não precisaremos ficar instanciando o objeto Session toda vez que precisarmos acessar o banco. O próprio netbeans tem um assistente que gera automaticamente essa classe.
package util;
import org.hibernate.Session;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.SessionFactory;
/**
* Hibernate Utility class with a convenient method to get Session object.
*
* @author lucas
*/
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() {
return sessionFactory.openSession();
}
}
Agora criaremos um Dao genérico com os métodos padrão em todos os DAO’s, evitando assim o trabalho de implementar os mesmos métodos em todos os DAO’s.
package Dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import util.HibernateUtil;
/**
*
* @author lucas
*/
public class Dao<T> {
private Class classe;
private Session session;
protected Session getSession() {
return session;
}
public Dao(Class classe) {
this.session = HibernateUtil.getSession();
this.classe = classe;
}
public void salvar(T objeto){
session.save(objeto);
}
public void remover(T objeto){
Transaction ts = session.beginTransaction();
session.save(objeto);
ts.commit();
}
public void atualizar(T objeto){
Transaction ts = session.beginTransaction();
session.update(objeto);
ts.commit();
}
public T load(long id){
return (T) session.load(classe, id);
}
}
Utilizamos na declaração da classe o tipo parametrizado T (de type), indicando que essa classe terá um tipo de Objeto.
No seu construtor, ela receberá um objeto que definirá o tipo usado na classe e utiliza o HibernateUtil para receber uma session. Observe que o método getSession() do Dao genérico é protected pois suas classes filhas precisarão acessa-lo para seus próprios métodos.
Agora criaremos o ClienteDao, que herdará todos os métodos do Dao genérico, sendo assim não será necessário criar os métodos básicos (Salvar, Atualzar, Remover e Carregar).
package Dao;
import java.util.Collection;
import modelo.Cliente;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
/**
*
* @author lucas
*/
public class ClienteDao extends Dao<Cliente> {
public ClienteDao(){
super(Cliente.class);
}
public Collection<Cliente> buscaPorNome(String nome){
Criteria c = getSession().createCriteria(Cliente.class);
c.add(Restrictions.ilike("nome", nome));
c.addOrder(Order.asc("idade"));
return c.list();
}
public int qtdeTotalCliente(){
Criteria c = getSession().createCriteria(Cliente.class);
c.setProjection(Projections.rowCount());
return (Integer) c.uniqueResult();
}
public int totalSaldo(){
Criteria c = getSession().createCriteria(Cliente.class);
c.setProjection(Projections.sum("saldo"));
return (Integer) c.uniqueResult();
}
}
Agora conheceremos o poder da API Criteria.
No método buscaPorNome, é recebido como parametro uma String que representa o nome do Cliente a ser buscado.
Em seguida é criado o objeto Criteria, através do método createCriteria() e esse recebe como argumento o tipo de objeto a ser pesquisado, como o objeto está mapeado para uma tabela do banco (eu não demonstrei aqui como mapear, porque como disse não é o objetivo do artigo) a API Criteria já sabe exatamente em qual(is) tabela(s) buscar.
Na linha seguinte utilizamos o método add() para refirnarmos a busca, no nosso caso adicionamos uma restrição através do ilike() do objeto Restrictions e passamos dois parâmetros o primeiro é o campo que será aplicada a restrição e o segundo o valor da restrição. Então no nosso caso informamos que queremos apenas os registros com o campo nome igual ao valor da variável nome.
Para melhorar ainda mais a busca, podemos definir a ordem que os objetos será apresentados. Para isso na linha seguinte usamos o método addOrder() e usamos o objeto Order para definir a ordem, que no nosso caso será o campo idade.
Na linha seguinte é usado o método list() que retorna uma lista de objetos que se encaixa no perfil informado ou null caso não encontre nada.
No método qtdeTotalCliente() é retornado um inteiro com a quantidade total de registro de Clientes salvos no banco. Para isso é utilizado o método setProjection e é passado como parâmetro o que queremos fazer, no caso utilizamos o método rowCount() do Projections para contar a quantidade de registros.
Para finalizar usamos o uniqueResult() para retornar a quantidade de registros.
E para finalizar o artigo, no totalSaldo() estamos utilizando também o setProjection para somar os valores de um determinado campo de todos os registros do banco, para isso utilizamos o método sum() do objeto Projections
Bom, no geral é isso. A API Criteria é muito poderosa, podemos ser utilizada para realizar (quase) todas as queries que você desejar, porém muita gente acha mais rápido e produtivo escrever as queries utilizando a HQL (Hibernate Querie Language) que irei mostrar no próximo artigo.



Comentários