Você está na página 1de 22

Conexo Java 2006 Mini-curso Hibernate

Srgio Lus Lopes Jnior


Caelum www.caelum.com.br

Neste tutorial, voc ir aprender a: - usar a ferramenta de ORM Hibernate - gerar as tabelas em um banco de dados qualquer a partir de suas classes de modelo - automatizar o sistema de adicionar, listar, remover e procurar objetos no banco - utilizar anotaes para facilitar o mapeamento de classes para tabelas - criar classes de dao bem simples utilizando o hibernate - utilizar relacionamentos entre tabelas

Introduo
A utilizao de cdigo SQL dentro de uma aplicao agrava o problema da independncia de plataforma de banco de dados e complica, em muito, o trabalho de mapeamento entre classes e banco de dados relacional.
HIBERNATE

O Hibernate abstrai o cdigo SQL da nossa aplicao e permite escolher o tipo de banco de dados enquanto o programa est rodando, permitindo mudar sua base sem alterar nada no seu cdigo Java. Alm disso, ele permite criar suas tabelas do banco de dados de um jeito bem simples, no se fazendo necessrio todo um design de tabelas antes de desenvolver seu projeto que pode ser muito bem utilizado em projetos pequenos. J projetos grandes onde o plano de ao padro tomado pelo Hibernate no satisfaz as necessidades da empresa (como o uso de select *, joins etc), ele possui dezenas de otimizaes que podem ser feitas para atingir tal objetivo. O Hibernate o framework de mapeamento objeto relacional mais utilizado em projetos Java. Seu criador Gavin King se juntou a Marc Flery do grupo JBoss, e agora o Hibernate faz parte do JBoss group, que por sua vez foi vendido para a corporao Red Hat.

Anotaes, EJB3 e Persistence API


Fazer o mapeamento objeto relacional com o Hibernate era muito trabalhoso at a chegada das anotaes do java5: voc precisava criar arquivos XML de mapeamento, especificando as relaes entre as entidades, nome de colunas, tabelas e muitos outros. Para no fazer isso tudo na mo o XDoclet ajudava muito, porm abria espao para erros de digitao. Muitos plugins para as IDEs foram lanados, mas faltava algo para criar uma real facilidade. A JSR 220, que especifica o EJB3, separou a parte de Entity Beans na Persistence API (javax.persistence), onde define um EntityManager que faz o papel das antiga Homes, assim como uma EJB query language renovada e um conjunto de anotaes

para fazer o mapeamento objeto relacional. Essa API desacoplada da API dos EJBs, fazendo com que a API no precise de um container Java EE para ser utilizado. Gavin King, como um dos lderes dessa JSR, foi implementando a Persistence API em cima do Hibernate enquanto a JSR ia sendo desenvolvida. Dia 1o de maio de 2006, com o lanamento da JSR, o Hibernate j possui implementado a grande maioria das necessidades especificadas na JSR. Por esse motivo uma grande parte de imports que vamos usar sero javax.persistence e no apenas org.hibernate.

Ambiente usado
Usaremos neste projeto a IDE livre Eclipse (www.eclipse.org) e Java 5. A verso do Hibernate que usamos a 3.2.1. Como Banco de Dados, usaremos o Apache Derby, um banco escrito totalmente em Java e que pode ser distribudo junto com sua aplicao.

Criando seu projeto


Para criar seu projeto, necessrio baixar os arquivos .jar necessrios para rodar o Hibernate e coloc-los no classpath do mesmo. O site oficial do hibernate o www.hibernate.org e l voc pode baixar a ltima verso estvel do mesmo na seo Download. Aps descompactar esse arquivo, basta copiar todos os jars para o nosso projeto.
HIBERNATE ANNOTATIONS

Ainda falta baixar as classes correspondentes ao HibernateAnnotations, que iremos utilizar para gerar o mapeamento entre as classes Java e o banco de dados. Eles so encontrados tambm no site do hibernate e contem outros jars que devemos colocar no nosso projeto.

Exerccio
1) Abra o eclipse e selecione o workspace padro. 2) Crie um novo projeto Java: File -> New -> Project -> Java Project Clique em Next e na prxima tela marque: Project name: hibernate Create separate source and output folders Clique em Finish. 3) Crie uma pasta lib dentro do seu projeto: Clique com o boto direito no nome do projeto e v em New -> Folder e crie uma pasta chamada lib 4) Copie os jars do hibernate, hibernate-annotations e do derby para o seu diretrio lib: - Clique com o boto direito na pasta lib e clique em Import - Selecione Archive File (na aba General), clique em Next - Selecione o arquivo hibernate-jar.zip

- Clique em Select All e depois em Finish 5) Precisamos adicionar os jars no class path. Expanda a pasta lib e selecione todos os jars. Clique com o boto direito e v em: Build Path -> Add to build path...

Propriedades do banco
O arquivo hibernate.properties um arquivo de propriedades para configurarmos as opes do hibernate. H centenas de configuraes possveis, como avanados controles de cache, transaes e outros. Para nosso sistema, precisamos de quatro linhas bsicas, que configuram o banco, o driver, o usurio e senha, que j conhecemos, e uma linha adicional, que diz para o hibernate qual dialeto de SQL ele deve falar: o dialeto do hsqldb. Alm disso, vamos colocar uma opo para que o hibernate exiba os comandos SQL que ele executar. O arquivo final fica da seguinte maneira: hibernate.dialect org.hibernate.dialect.DerbyDialect hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver hibernate.connection.url jdbc:derby:bancodedados;create=true hibernate.connection.username hibernate.connection.password hibernate.show_sql true hibernate.format_sql true Ele deve ser colocado no classpath de sua aplicao. No nosso caso, basta coloclo no diretrio src. Alm disso, vamos copiar tambm um arquivo chamado log4j.properties para configurar o log do hibernate; usamos o arquivo padro que vem junto com o hibernate.

Exerccios
1-) Para economizarmos tempo, copie o arquivo properties citado acima para dentro do diretrio src de nosso projeto: Clique com o boto direito na pasta src e clique em Import Selecione Archive File (na aba General), clique em Next Selecione o arquivo hibernate-properties.zip Clique em Select All e depois em Finish

2) Abra o arquivo hibernate.properties copiado e veja seu contedo.

Em casa: Baixando os arquivos necessrios


V em www.hibernate.org e baixe o hibernate e o hibernate-annotations. Descompacte os dois arquivos baixados. Os jars necessrios esto na raiz de cada pasta criada e dentro de suas respectivas pastas lib. Os arquivos hibernate.properties e o log4j.properties esto na pasta src dentro da pasta onde voc descompactou o hibernate. O Derby voc baixa em derby.apache.org. Copie o arquivo derby.jar de dentro da

pasta lib dele.

Modelo
Como exemplo, vamos criar um sistema de controle de Produtos para uma loja. Iniciamos nosso trabalho modelando uma classe para representar essa entidade Produto do sistema. A classe produto ser uma classe JavaBean simples, como atributos privados e mtodos de acesso get e set. package br.com.caelum.hibernate; public class Produto { private private private private } Alm de termos a classe modelando a entidade Produto no nosso programa Java, precisamos de alguma forma de persist-lo no banco de dados. Normalmente, criaramos a tabela em SQL (create table ...) para guardar os produtos. Vamos usar o hibernate para isso. Mas antes precisamos configurar a classe para o hibernate saber us-la. Long id; String nome; String descricao; double preco;

// gets e sets aqui

Configurando a classe/tabela Produto


Antigamente (at a verso 2 do hibernate) a configurao era feito somente atravs de arquivos xml, o que era bem chato, e utilizvamos de uma ferramenta chamada Xdoclet que criava tais xmls atravs de comentrios especiais. Hoje em dia o Xdoclet foi substituido pelas anotaes do Java 5. A grande diferena entre os dois anotaes e comentrios que as anotaes so bem estruturadas, seguem um padro e so mantidas em tempo de execuo, enquanto os comentrios so perdidos em tempo de compilao, que impossibilita descobrir em tempo de execuo o que havia sido comentado. O cdigo a seguir coloca nossa classe na tabela "Produto" e seta algumas propriedades e o id (chave primria). Ateno: toda classe que vai trabalhar com o Hibernate precisa de um (ou mais) campo(s) que ser(o) a chave primria (composta ou no). package br.com.caelum.hibernate; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Produto {

@Id @GeneratedValue private Long id; private String nome; private String descricao; private double preco; } // gets e sets aqui A especificao do EJB3 define tais anotaes e possui diversas opes que podemos utilizar em nosso projeto. Sempre que possuir alguma dvida em relao as anotaes lembre-se de ler a tal especificao. O API comum das anotaes usadas pelo Hibernate e o EJB3 o Java Persistence API, no pacote javax.persistence.

Exerccios
1-) Crie uma classe chamada Produto no pacote br.com.caelum.hibernate: File -> New -> Class Coloque o nome do pacote como br.com.caelum.hibernate Coloque o nome da classe como Produto 2) Escreva a classe como vimos acima: package br.com.caelum.hibernate; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Produto { @Id @GeneratedValue private Long id; private String nome; private String descricao; private double preco; } 3-) Gere os getters e setters usando o eclipse: - Selecione os atributos da classe e v em: - Source -> Generate Getters and Setters - Clique em Select All e depois em Finish.

Configurando

Qualquer programa que use o hibernate precisa, antes de qualquer coisa, cofigur-lo. Fazemos isso atravs da classe AnnotationConfiguration. // cria a configurao do hibernate AnnotationConfiguration conf = new AnnotationConfiguration(); A partir da podemos adicionar quantas classes desejarmos a nossa configurao. // adiciona a classe Produto conf.addAnnotatedClass(Produto.class); O Hibernate requer que descrevamos como a classe se relaciona com as tabelas no banco de dados e fizemos isso atravs das anotaes do Hibernate. Ao adicionarmos a classe Produto na nossa configurao, o Hibernate l essas configuraes.

XML
Essa configurao poderia ser feita atravs de um arquivo xml chamado hibernate.cfg.xml, e em vez de utilizarmos as chamadas ao mtodo addAnnotatedClass iramos executar o mtodo configure() .

Criando as tabelas
SCHEMA EXPORT

Vamos criar um programa que gera as tabelas do banco. Dada uma configurao, a classe SchemaExport capaz de gerar o cdigo DDL de criao de tabelas em determinado banco (no nosso caso, o hsqldb). Para exportar tais tabelas, fazemos uso do mtodo create que recebe dois argumentos booleanos. O primeiro diz se desejamos ver o cdigo DDL e o segundo se desejamos execut-lo realmente. // gera a tabela no banco new SchemaExport(conf).create(true, true); O cdigo final da classe GeraTabelas, incluindo a configurao, voc v no exerccio abaixo:

Exerccios
1-) Crie a classe GeraTabelas: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como GeraTabelas 2) Escreva o mtodo main e, dentro dele, faa a configurao do hibernate e depois gere a tabela, da seguinte forma: package br.com.caelum.hibernate; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport; public class GeraTabelas { public static void main(String[] args) {

// cria a configurao do hibernate AnnotationConfiguration conf = new AnnotationConfiguration(); // adiciona a classe Produto conf.addAnnotatedClass(Produto.class); // gera a tabela no banco new SchemaExport(conf).create(true, true);

} }

3-) Crie suas tabelas executando o cdigo anterior. Clique com o boto direito no nome da classe, v em: Run As... -> Java Application O Hibernate deve reclamar que no configuramos nenhum arquivo de log para ele (dois warnings, ignore-os) e mostrar o cdigo SQL que ele executou no banco.

Sesses
O hibernate np te d acesso direto s conexes com o banco de dados. Ele trabalha com a idia de sesses de uso do banco. Para efetuar alguma operao no banco (INSERT, SELECT, ...) voc precisa, antes, obter uma sesso do hibernate. O Hibernate prov uma fbrica de sesses, onde voc pode obter uma sesso quando quiser. Na configurao do hibernate, chamamos o mtodo buildSessionFactory() que nos devolve uma SessionFactory. SessionFactory factory = conf.buildSessionFactory(); factory.close(); O Hibernate gera sesses atravs dessa factory. Essas sesses so responsveis por se conectar ao banco de dados e persistir e buscar objetos no mesmo. A maneira mais simples de abrir uma nova sesso e fechar a mesma : Session session = factory.openSession(); session.close();

Hibernate Session Factory


Sempre que formos trabalhar com o Hibernate, teremos que configur-lo, obter a fbrica de sesses e depois obter uma sesso. Ao invs de espalhar esse cdigo por todo nosso sistema, vamos encapsul-lo em algum lugar, em alguma classe. Vamos criar uma classe HibernateFactory que cuidar de: - instanciar a SessionFactory do Hibernate; - nos dar Sessions do hibernate quando precisarmos. package br.com.caelum.hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory;

import org.hibernate.cfg.AnnotationConfiguration; public class HibernateFactory { private static SessionFactory factory; static { AnnotationConfiguration cfg = new AnnotationConfiguration(); cfg.addAnnotatedClass(Produto.class); factory = cfg.buildSessionFactory(); } public Session getSession() { return factory.openSession(); } } O bloco esttico das linhas 4 a 8 cuidar de configurar o Hibernate e pegar uma SessionFactory. Lembre-se que o bloco esttico executado automaticamente quando a classe carregada pelo Class Loader e s neste momento; ele no ser executado outras vezes, como quando voc der new HibernateFactory(). Ou seja, a configurao do Hibernate ser feita uma nica vez em todo seu programa. O mtodo getSession SessionFactory do Hibernate. devolver uma Session, conseguida atravs do

Exerccios
1-) Crie a classe HibernateFactory: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como HibernateFactory 2-) Implemente a classe HibernateFactory como est na seo anterior. No momento de importar Session lembre-se que no a classic! package br.com.caelum.hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; public class HibernateFactory { private static SessionFactory factory; static { AnnotationConfiguration cfg = new AnnotationConfiguration(); cfg.addAnnotatedClass(Produto.class); factory = cfg.buildSessionFactory(); }

public Session getSession() { return factory.openSession(); } }

Erros comuns
1-) O erro mais comum ao criar a classe HibernateFactory est em importar org.hibernate.classic.Session ao invs de org.hibernate.Session. Uma vez que o mtodo openSession devolve uma Session que no do tipo classic, o Eclipse pede para fazer um casting. No faa o casting! Remova o seu import e adicione o import correto.

Salvando novos objetos


Depois de todos esses passos de configurao e etc, vamos agora efetivamente trabalhar com o banco de dados, inserindo um novo Produto. Atravs de um objeto do tipo Session possvel gravar novos objetos do tipo Produto no banco. Para tanto basta criar o objeto e depois utilizar o mtodo save. Mas como usamos um banco transacional, precisamos usar Transaes. Isso feito com o beginTransaction() na session e depois com o commit() para comitar. // cria um produto p e o popula Produto p = new Produto(); p.setNome("Nome aqui"); p.setDescricao("Descrio aqui"); p.setPreco(100.50); // obtm uma sesso Session session = new HibernateFactory().getSession(); // Inicia uma transao Transaction transaction = session.beginTransaction(); // salva o produto session.save(p); // Comita a transao transaction.commit(); // veja o id gerado System.out.println("ID do produto: " + p.getId()); session.close();

Exerccios
1-) Crie a classe AdicionaProduto: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate

E o nome da classe como AdicionaProduto 2) Implemente o mtodo main para adicionar um produto no banco de dados, conforme vimos acima: package br.com.caelum.hibernate; import org.hibernate.Session; public class AdicionaProduto { public static void main(String[] args) { // cria um produto p e o popula Produto p = new Produto(); p.setNome("Nome aqui"); p.setDescricao("Descrio aqui"); p.setPreco(100.50); // obtm uma sesso Session session = new HibernateFactory().getSession(); // Inicia uma transao Transaction transaction = session.beginTransaction(); // salva o produto session.save(p); // Comita a transao transaction.commit(); // veja o id gerado System.out.println("ID do produto: " + p.getId()); session.close(); } } 3-) Adicione um produto executando o cdigo anterior. Clique com o boto direito no nome da classe, v em: Run As... -> Java Application O Hibernate deve mostrar o cdigo SQL que ele executou no banco. 4-) (opcional) Adicione outros produtos no banco (altere os dados no programa e rode-o outras vezes).

Buscando pelo id
Para buscar um objeto pela chave primria, no caso o seu id, utilizamos o mtodo load, conforme o exemplo a seguir: // procura o produto de id 2 Produto p = (Produto) session.load(Produto.class, 1L);

// imprime o nome do Produto System.out.println(p.getNome());

Exerccio
1) Crie uma classe BuscaProduto: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como BuscaProduto 2) Crie o mtodo main e busque um Produto pelo id: package br.com.caelum.hibernate; import org.hibernate.Session; public class BuscaProduto { public static void main(String[] args) { // obtm uma sesso Session session = new HibernateFactory().getSession(); // procura o produto de id 2 Produto p = (Produto) session.load(Produto.class, 1L); // imprime o nome do Produto System.out.println(p.getNome()); } } 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application session.close();

Listando todos os produtos


Vamos listar todos os produtos existentes no banco de dados. Para isso, vamos usar o mtodo createCriteria de Session que cria um Criteria. Atravs de um Criteria, temos acesso a diversas operaes no banco de dados; uma delas listar tudo com o mtodo list(). Dada uma Session, para listarmos todos os produtos fazemos: // obtm lista de todos os produtos List<Produto> produtos = session.createCriteria(Produto.class).list(); Depois, basta percorrer essa lista e imprimir todos os nomes, por exemplo: // percorre os produtos e imprime o nome de cada um for (Produto p : produtos) { System.out.println(p.getNome()); }

Exerccio

1) Crie uma classe ListaProdutos: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como ListaProdutos 2) Crie o mtodo main e busque todos os produtos do banco: package br.com.caelum.hibernate; import java.util.List; import org.hibernate.Session; public class ListaProdutos { public static void main(String[] args) { Session session = new HibernateFactory().getSession(); // obtm lista de todos os produtos List<Produto> produtos = session.createCriteria(Produto.class).list(); // percorre os produtos e imprime o nome de cada um for (Produto p : produtos) { System.out.println(p.getNome()); } } } 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application session.close();

Buscando com WHERE em HQL


No exemplo anterior, usamos a chamada Criteria API, uma API do hibernate que permite que busquemos no banco atravs da chamada de mtodos, sem escrever SQL. Embora a Criteria API seja muito poderosa e seja virtualmente possvel fazer tudo com ela, h ainda uma segunda possibilidade que eventualmente pode ser mais simples e direta: o uso de uma linguagem de queries como o SQL. O problema de usarmos SQL diretamente, porm, que, como vimos, ele dependente de banco de dados. Para solucionar isso, o hibernate criou uma linguagem de queries prpria, a HQL, ou Hibernate Query Language. A grande vantagem que ela extremamente semelhante ao SQL que estamos acostumados mas portvel. Ou seja, na hora de executar realmente no banco, o hibernate traduz o comando HQL para o SQL especfico do banco em questo. Para buscarmos os produtos usando alguma clusula WHERE, por exemplo buscar apenas os produtos de id maior que 1, podemos fazer: // obtm lista dos produtos com id maior que 1 List<Produto> produtos = session.createQuery("from Produto where id > 1").list();

Exerccio
1) Crie uma classe ListaProdutosHQL: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como ListaProdutosHQL 2) Crie o mtodo main e busque no banco os produtos com id maior que 1 usando HQL: package br.com.caelum.hibernate; import java.util.List; import org.hibernate.Session; public class ListaProdutosHQL { public static void main(String[] args) { Session session = new HibernateFactory().getSession(); // obtm lista dos produtos com id maior que 1 List<Produto> produtos = session.createQuery("from Produto where id > 1").list(); // imprime nome e id de cada produto for (Produto p : produtos) { System.out.println(p.getId() + " - " + p.getNome()); } session.close(); } }

3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application

Remoo (DELETE)
Assim como inserir usando o Hibernate muito simples, remover tambm bastante simples. Basta chamarmos o mtodo delete() na session passando o objeto que queremos remover. No nosso caso, passamos o Produto a ser removido. Cuidado que, assim como em um DELETE normal, sempre que vamos remover algum precisamos dizer qual o id dele. Ento nosso Produto precisa estar com o id setado. No se esquea tambm que precisamos de uma Transaction para executar algo no banco. O cdigo final fica: // cria um Produto e seta seu id Produto p = new Produto(); p.setId(0L); // lembre que id um Long! // obtm sesso Session session = new HibernateFactory().getSession();

// abre transao Transaction transaction = session.beginTransaction(); // apaga o produto session.delete(p); // comita a transao transaction.commit(); session.close();

Exerccio
1) Crie uma classe RemoveProduto: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como RemoveProduto 2) Crie o mtodo main e remova o produto de id 0: package br.com.caelum.hibernate; import org.hibernate.Session; import org.hibernate.Transaction; public class RemoveProduto { public static void main(String[] args) { // cria um Produto e seta seu id Produto p = new Produto(); p.setId(0L); // lembre que id um Long! // obtm sesso Session session = new HibernateFactory().getSession(); // abre transao Transaction transaction = session.beginTransaction(); // apaga o produto session.delete(p); // comita a transao transaction.commit(); session.close(); } } 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application

Uma categoria
E se cada Produto na nossa loja tivesse uma Categoria? Ou seja, um relacionamento muitos para um? Com o hibernate, muito fcil criar relacionamentos

entre entidades. Comeamos criando uma classe para representar uma Categoria com, por exemplo, id e nome. Como ela uma classe a ser gerenciada pelo Hibernate, marcamos as anotaes apropriadas. A classe final ficar assim: package br.com.caelum.hibernate; import import import import javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.GenerationType; javax.persistence.Id;

@Entity public class Categoria { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String nome; } // gets e sets Repare que ela muito parecida com a classe Produto.

Exerccio
1-) Crie uma classe chamada Categoria no pacote br.com.caelum.hibernate: File -> New -> Class Coloque o nome do pacote como br.com.caelum.hibernate Coloque o nome da classe como Categoria 2) Escreva a classe como vimos acima: package br.com.caelum.hibernate; import import import import javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.GenerationType; javax.persistence.Id;

@Entity public class Categoria { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; } private String nome;

3-) Gere os getters e setters usando o eclipse:

- Selecione os atributos da classe e v em: - Source -> Generate Getters and Setters - Clique em Select All e depois em Finish.

Produto tem uma Categoria


No nosso sistema, cada Produto possui uma Categoria. Em Java, representamos isso com um atributo na classe Produto. Ou seja, colocamos um atributo do tipo Categoria dentro de Produto (e geramos get e set para ele). Mas precisamos, alm disso, instruir o hibernate de que estamos fazendo na verdade um relacionamento Muitos para Um no banco de dados tambm. Fazemos isso com uma anotao simples, a @ManyToOne no atributo categoria. A classe Produto, com as modificaes fica: package br.com.caelum.hibernate; import import import import import javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.GenerationType; javax.persistence.Id; javax.persistence.ManyToOne;

@Entity public class Produto { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String nome; private String descricao; private double preco; @ManyToOne private Categoria categoria; } // gets e sets aqui

Exerccio
1) Abra sua classe Produto. Acrescente um atributo do tipo Categoria chamado categoria. Marque esse atributo com a anotao @ManyToOne: @ManyToOne private Categoria categoria; 2) Gere get e set para este novo atributo. Selecione o atributo que voc acabou de criar e v em: - Source -> Generate Getters And Setters - Cliquem em Select All e depois em Finish

3) O cdigo final de sua classe Produto deve estar assim: package br.com.caelum.hibernate; import import import import import javax.persistence.Entity; javax.persistence.GeneratedValue; javax.persistence.GenerationType; javax.persistence.Id; javax.persistence.ManyToOne;

@Entity public class Produto { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id; private String nome; private String descricao; private double preco; @ManyToOne private Categoria categoria; } // gets e sets aqui

Recriando as tabelas
Agora que adicionamos um campo novo na tabela Produto e criamos uma nova classe a ser persistida pelo hibernate, precisamos recriar as tabelas. Vamos usar a classe GeraTabelas que fizemos anteriormente. Precisamos apenas indicar, na nossa configurao, que agora temos, alm de Produto, tambm Categoria: // cria a configurao do hibernate AnnotationConfiguration conf = new AnnotationConfiguration(); // adiciona as entidades conf.addAnnotatedClass(Produto.class); conf.addAnnotatedClass(Categoria.class); // gera o esquema do banco new SchemaExport(conf).create(true, true);

Exerccio
1) Abra sua classe GeraTabelas. Logo depois de adicionar o Produto configurao, adicione a Categoria tambm. O cdigo final de sua classe deve ser: package br.com.caelum.hibernate; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport;

public class GeraTabelas { public static void main(String[] args) { // cria a configurao do hibernate AnnotationConfiguration conf = new AnnotationConfiguration(); // adiciona as entidades conf.addAnnotatedClass(Produto.class); conf.addAnnotatedClass(Categoria.class); // gera o esquema do banco new SchemaExport(conf).create(true, true); } } 2) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application

Adicionar um produto com categoria


Que tal adicionar um Produto que possua uma Categoria? Podemos fazer isso facilmente com o Hibernate, usando o mtodo save na session(). Mas antes, lembre de alterar a nossa classe HibernateFactory para tambm incluir a configurao da classe Categoria, assim como fizemos no GeraTabelas. A classe HibernateFactory no final ficar assim: package br.com.caelum.hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; public class HibernateFactory { private static SessionFactory factory; static { AnnotationConfiguration cfg = new AnnotationConfiguration(); cfg.addAnnotatedClass(Produto.class); cfg.addAnnotatedClass(Categoria.class); factory = cfg.buildSessionFactory(); } public Session getSession() { return factory.openSession(); } } Para adicionarmos um Produto com alguma Categoria, primeiro criamos uma Categoria: Categoria c = new Categoria(); c.setNome("Uma categoria"); E criamos um Produto:

Produto p = new Produto(); p.setNome("Nome do produto"); p.setDescricao("Sua descricao"); p.setPreco(123.00); Como dizer agora que o Produto p da Catgoria c? Basta chamar o setCategoria! p.setCategoria(c); Apenas isso! Agora basta obtermos a session, abrirmos uma transao, salvarmos a categoria e depois salvarmos o produto. S isso! Session session = new HibernateFactory().getSession(); Transaction transaction = session.beginTransaction(); session.save(c); session.save(p); transaction.commit(); session.close();

Exerccio
1) Crie uma classe AdicionaProdutoComCategoria: V em File -> New -> Class Coloque o pacote como br.com.caelum.hibernate E o nome da classe como AdicionaProdutoComCategoria 2) Crie o mtodo main e implemente o cdigo visto acima: package br.com.caelum.hibernate; import org.hibernate.Session; import org.hibernate.Transaction; public class AdicionaProdutoComCategoria { public static void main(String[] args) { Categoria c = new Categoria(); c.setNome("Uma categoria"); Produto p = new Produto(); p.setNome("Nome do produto"); p.setDescricao("Sua descricao"); p.setPreco(123.00); p.setCategoria(c); Session session = new HibernateFactory().getSession(); Transaction transaction = session.beginTransaction(); session.save(c); session.save(p); transaction.commit(); session.close(); }

} 3) Rode a classe e observe o SQL gerado pelo Hibernate: - Clique com o boto direito na classe e v em: Run as -> Java Application

Adicional: lista os produtos e sua categoria


Como fazer agora a listagem de produtos listar tambm o nome da categoria do produto? Joins? Com hibernate, basta acessarmos no produto, o getCategoria() e depois o getNome(): p.getCategoria().getNome() Sem complicao! O Hibernate se vira com o join que precisar fazer. Na nossa classe ListaProdutos bastaria alterar o for para imprimir o nome da categoria tambm, s isso! Veja o cdigo completo do ListaProdutos aps a modificao (note que a nica modificao necessria est em amarelo): package br.com.caelum.hibernate; import java.util.List; import org.hibernate.Session; public class ListaProdutos { public static void main(String[] args) { Session session = new HibernateFactory().getSession(); // obtm lista de todos os produtos List<Produto> produtos = session.createCriteria(Produto.class).list(); // percorre os produtos e imprime o nome de cada um for (Produto p : produtos) { System.out.println( p.getNome() + ", categoria: " + p.getCategoria().getNome()); } session.close(); } }

Adicional: Exerccios para o preguioso


1-) Teste um programa que faz somente o seguinte: busca um produto por id. O cdigo deve somente buscar o produto e no imprimir nada! Qual o resultado?
Session session = new HibernateFactory().getSession(); Produto encontrado = (Produto) session.load(Produto.class,new Long(1));

2-) Tente imprimir o nome do produto do teste anterior, o que acontece?


Session session = new HibernateFactory().getSession(); Produto encontrado = (Produto) session.load(Produto.class,new Long(1)); System.out.println(encontrado.getNome());

3-) Antes de imprimir o nome do produto, tente imprmir uma mensagem qualquer, do tipo: O select j foi feito. E agora? Como isso possvel?

Session session = new HibernateFactory().getSession(); Produto encontrado = (Produto) session.load(Produto.class,new Long(1)); System.out.println(O select j foi feito); System.out.println(encontrado.getNome());

Ento, onde est o cdigo do select? Ele deve estar no mtodo getNome(), certo? 4-) Imprima o nome da classe do objeto referenciado pela varivel encontrado:
Session session = new HibernateFactory().getSession(); Produto encontrado = (Produto) session.load(Produto.class,new Long(1)); System.out.println(O select j foi feito); System.out.println(encontrado.getNome()); System.out.println(encontrado.getClass().getName());

O Hibernate retorna um objeto cujo tipo estende Produto: ele no deixa de ser um Produto mas no somente um Produto. O mtodo getNome() foi sobrescrito nessa classe para fazer a busca na primeira vez que chamado, economizando tempo de processamento. claro que para fazer o fine-tuning do Hibernate interessante conhecer muito mais a fundo o que o Hibernate faz e como ele faz isso.

Adicional: Fazer paginao


Usando a classe ListaProdutos temos a lista com todos os produtos no banco de dados. Em um sistema com listagens longas, normalmente apresentamos a lista por pginas. Para implementar paginao, precisamos determinar que a listagem deve comear em um determinado ponto e ser de um determinado tamanho. Usando o Criteria, como anteriormente, isso bastante simples. Podemos fazer o seguinte: List<Produto> produtos = session.createCriteria(Produto.class) .setFirstResult(0).setMaxResults(2).list(); O mtodo setMaxResults determina o tamanho da lista (resultados por pgina) e o mtodo setFirstResult determina em que ponto a listagem deve ter incio. Por fim, basta chamar o mtodo list() e a listagem devolvida ser apenas daquela pgina! No nosso caso estamos listando a partir do primeiro mas apenas 2 resultados.

Adicional: Atualiza (UPDATE)


Assim como save e delete, podemos fazer o update chamando o mtodo update() na session e passando o produto a ser atualizado. Lembre que, para um update no banco, alm dos dados normais, precisamos do id. O cdigo final, com controle de transaes fica: package br.com.caelum.hibernate; import org.hibernate.Session; import org.hibernate.Transaction; public class AtualizaProduto {

public static void main(String[] args) { // cria um Produto Produto p = new Produto(); p.setId(1L); // lembre que id um Long! p.setNome("Novo nome"); p.setDescricao("Nova descricao"); p.setPreco(78.50); // obtm sesso Session session = new HibernateFactory().getSession(); // abre transao Transaction transaction = session.beginTransaction(); // atualiza o produto session.update(p); // comita a transao transaction.commit(); session.close(); } }

Você também pode gostar