Вы находитесь на странице: 1из 9

Introduo

No ltimo captulo vimos como criar uma entidade e mape-la para o banco de dados. Usamos as anotaes tpicas: @Entity, @Id e @GeneratedValue. Depois definimos atravs do persistence.xml as configuraes mais genricas, como o

provedor(ou Provider), a conexo com o banco de dados e as propriedades do Hibernate. Nos exerccios criamos a classeJPAUtil que ajuda na inicializao do JPA, garantindo que exista apenas uma EntityManagerFactory. Ento, testamos uma vez

o EntityManager persistindo uma conta no banco de dados. Nesse captulo vamos focar nos mtodos mais importantes do EntityManager. Para facilitar, inserimos algumas contas no banco atravs da classe PopulaConta. Ao selecionarmos todos os dados da tabela Conta no console do MySQL, aparecero cinco registros. Criamos tambm a classe TesteEstadosJPA para os teste neste captulo.

Carregar entidade pela chave primria


Entre as funcionalidades mais importantes, no podia faltar a de carregar uma entidade por sua chave primria. O EntityManager prov o mtodo find com essa finalidade. O find recebe dois parmetros. O primeiro a classe da entidade que queremos carregar e, o segundo, o valor da chave primria. Para carregar uma conta com o Id 1, por exemplo, usaremos:
manager.find(Conta.class, 1);

O retorno um objeto da classe conta inicializado com os valores do banco de dados:

Conta conta = manager.find(Conta.class, 1);

Cuidado! O tipo da chave primria deve bater com o tipo definido na classe Conta. No nosso caso, Integer. Antes de executar o mtodo main, vamos imprimir o titular da conta atravs de um simples System.out.println. Ao chamar o mtodo main, o JPA executa o select e devolve o objeto "conta" visvel no console.
Hibernate: select conta0_.id as id0_0_, conta0_.agencia as agencia0_0_, conta0_.banco as banco0_0_, conta0_.numero as numero0_0_,

conta0_.titular as titular0_0_ from Conta conta0_ where conta0_.id=? Maria dos Santos

Entidades gerenciadas - O estado Managed


No exemplo s acessamos a conta. Vamos alterar uma vez algum valor. Por exemplo, o titular:
conta.setTitular("Pedro Ferreira"); System.out.println(conta.getTitular());

Ao executar o mtodo main percebemos que a conta no s foi carregada, como tambm alterada. O JPA automaticamente sincronizou os dados da conta com o registro na tabela.
Hibernate: select conta0_.id as id0_0_, conta0_.agencia as agencia0_0_, conta0_.banco as banco0_0_, conta0_.numero as numero0_0_, conta0_.titular as titular0_0_ from Conta conta0_ where conta0_.id=? Pedro Ferreira Hibernate: update Conta set agencia=?, banco=?, numero=?, titular=? where id=?

O JPA verificou se houve alguma alterao na entidade e executou um update. O mtodo find devolveu um conta gerenciada(ou Managed) pelo JPA. Neste estado garantido que o objeto ter sua representao idntica no banco.

Repare que ao repetirmos a execuo, no ser feito nenhum update, pois a conta em memria agora igual a conta no banco de dados. O JPA faz uma verificao para determinar se realmente preciso executar o updade. Com o JPA, o objetivo sempre trazer os objetos para o estado Managed, j que assim eles sero gerenciados e automaticamente sincronizados com o banco.

Persistindo objetos transientes


Nem sempre queremos carregar um objeto que j exista no banco de dados. Alias, j vimos anteriormente como inserir uma nova conta no banco. Vamos analisar novamente o cdigo que usou o mtodo persist() do EntityManager. Vamos descomentar o cdigo e chamar novamente o persist().

public class TesteJPA { public static void main(String[] args) { Conta conta = new Conta(); conta.setTitular("Fabio Alameida"); conta.setBanco("HSBC"); conta.setNumero("123345"); conta.setAgencia("321"); EntityManager em = new JPAUtil().getEntityManager(); em.getTransaction().begin(); em.persist(conta); em.getTransaction().commit(); em.close();

Repare que a conta no existia no banco. Ela foi criada pela aplicao e at que fosse chamado o mtodo persist() do JPA, ela no seria salva no banco e sumiria totalmente se caso a aplicao terminasse. Esse estado chamadoTransiente(ou Transient) e a tarefa do mtodo persist() justamente alterar esse estado para Gerenciado(Managed).

Ou seja, s aps ter chamado o mtodo persist() que a nova conta passou para Managed e, a partir de agora, o JPA vai sincronizar todas as suas alteraes. Podemos provar isso alterando o nome do titular da conta aps ter chamado opersist():

em.persist(conta); conta.setTitular("Mario Santos");

Ao executar esse cdigo, percebemos na view console do Eclipse que foi gerado automaticamente um insert e depois umupdate para a conta. Novamente o JPA cuidou da entidade e sincronizou todas as suas alteraes. importante frisar que o estado Managed da entidade dura enquanto o EntityManager estiver aberto.

Atualizar objetos desatachados


Vamos fazer mais um teste: inserir uma nova conta no banco e depois de transform-la em Managed. Vamos imprimir seu Id. Podemos fazer isso facilmente como vimos anteriormente.
... em.persist(conta); System.out.println(conta.getId()); // imprime por exemplo 3

em.getTransaction().commit(); em.close()

Ao executar, o JPA recupera a Id que o banco reservou para essa entidade e a imprime no console. Mas, e se depois de fecharmos o EntityManager, quisermos atualizar esse objeto que j foi salvo uma vez? Vamos alterar os dados da conta, e colocar essa Id retornada no objeto conta alterado. Mudaremos o nmero e a agncia para depois tentar sincronizar com o dados de banco.
Conta conta = new Conta(); conta.setId(3); conta.setNumero("54321"); conta.setAgencia("3344"); ...

S temos um problema. Nesse caso a entidade no mais Transient, pois mesmo que a aplicao termine, a conta com a ID3 continua existindo no banco. JPA chama esse estado de Detached ou desatachado, pois a entidade j foi Managed um vez. Ela tem uma chave primria marcada, s que os dados entre o objeto e o registro no banco divergem.

Como vimos, a tarefa do desenvolvedor deixar as entidades Managed. Para fazer com que um objeto Detached volte a serManaged, devemos usar o mtodo merge().

Conta conta = new Conta(); conta.setId(3); // conta com a Id 3 j foi persistida anteriormente conta.setTitular("Mario Santos"); conta.setBanco("Itau"); conta.setNumero("54321"); conta.setAgencia("3344");

EntityManager em = new JPAUtil().getEntityManager(); em.getTransaction().begin();

em.merge(conta);

em.getTransaction().commit(); em.close();

Vamos executar uma vez e analisar o console. Foi feito um update, mas repare que antes o JPA executou um select para verificar se a atualizao era necessria.
Hibernate: select conta0_.id as id0_0_, conta0_.agencia as agencia0_0_, conta0_.banco as banco0_0_, conta0_.numero as numero0_0_, conta0_.titular as titular0_0_ from Conta conta0_ where conta0_.id=?

Hibernate:

update Conta set agencia=?, banco=?, numero=?, titular=? where id=?

Aqui tambm, o JPA s atualiza a conta se for necessrio. Se realmente h alguma diferena entre a conta em memria e a no banco de dados.

Removendo entidades pelo EntityManager


Por ltimo falta entender como remover uma entidade. Para tal, o JPA possui um mtodo remove() que recebe a entidade a ser removida. Vamos testar isso com a conta anteriormente criada:
Conta conta = new Conta(); conta.setId(3); // outros setters

EntityManager em = new JPAUtil().getEntityManager(); em.getTransaction().begin();

em.remove(conta);

em.getTransaction().commit(); em.close();

Ao executar recebemos para nossa supresa uma exceo: Exception in thread "main"
java.lang.IllegalArgumentException: br.com.caelum.financas.modelo.Conta#3 Removing a detached instance

A mensagem indica que a conta est desatachada (Detached) e sendo assim, no pode ser removida. Para remover qualquer entidade, ela precisa estar gerenciada (ou Managed). Ento vamos carregar a conta antes com o mtodo find() e depois vamos delet-la. Logo aps a chamada de remove(), o objeto no tem mais representao no banco, j que foi removido. Porm, o objeto continua existindo na memria, em um estado conhecido como Removed.

Resumo dos estados


Vimos nesse captulo os estados das entidades no JPA. O estado principal se chama Managed. Uma entidade nesse estado estar sempre sincronizada com o banco. Para deixar uma entidade Managed, usamos alguns mtodos do EntityManager. Vimos que o mtodo find() automaticamente devolve uma entidade Managed e a partir da, qualquer alterao ser refletida no banco. Uma entidade Transient - que nunca foi persistida antes - se torna Managed pelo mtodo persist(). Para passar uma entidade Detached para Managed usamos o mtodo merge(). Detached significa que aquela entidade j foi managed alguma vez, ou seja, j existe uma apresentao dela no banco de dados. Por fim, vimos que para remover uma entidade ela precisa estar managed para usarmos o mtodo remove().

Repare que o SQL gerado uma consequncia dos estados e dos valores das entidades. Vimos, por exemplo, que o mergepode causar um update ou simplesmente nenhuma

alterao no banco. Abrimos mo do SQL, mas em troca preciso dominar os estados do JPA.