algaworks ebook jpa e hibernate 1a edicao 20150731

Upload: user

Post on 01-Nov-2015

73 views

Category:

Documents


5 download

DESCRIPTION

Algaworks eBook Jpa e Hibernate 1a Edicao 20150731

TRANSCRIPT

  • www.princexml.comPrince - Non-commercial LicenseThis document was created with Prince, a great way of getting web content onto paper.

  • JPA e Hibernatepor Thiago Faria e Normandes Junior

    1 Edio, 31/07/2015

    2015 AlgaWorks Softwares, Treinamentos e Servios Ltda. Todos os direitosreservados.

    Nenhuma parte deste livro pode ser reproduzida ou transmitida em qualquerforma, seja por meio eletrnico ou mecnico, sem permisso por escrito daAlgaWorks, exceto para resumos breves em revises e anlises.

    AlgaWorks Softwares, Treinamentos e Servios [email protected]+55 (11) 2626-9415

    Siga-nos nas redes sociais e fique por dentro de tudo!

  • Sobre os autoresThiago Faria de AndradeFundador, instrutor e consultor da AlgaWorks.Graduado em Sistemas de Informao e certificadocomo programador Java pela Sun. Iniciou seuinteresse por programao em 1995, quandodesenvolveu um software para entretenimento e setornou um dos mais populares no Brasil e outros

    pases de lngua portuguesa. J foi scio e trabalhou em outras empresas desoftware como programador, gerente e diretor de tecnologia, mas nunca deixoude programar.

    LinkedIn: https://www.linkedin.com/in/thiagofa

    Normandes Jos Moreira JuniorScio e instrutor da AlgaWorks, formado emEngenharia Eltrica pela Universidade Federal deUberlndia e detentor das certificaes LPIC-1, SCJPe SCWCD. Palestrante internacional reconhecido porcontribuir e liderar projetos open source.

    LinkedIn: https://www.linkedin.com/in/normandesjr

  • Antes de comear...Antes que voc comece a ler esse livro, ns gostaramos de combinar algumascoisas com voc, para que tenha um excelente aproveitamento do contedo.Vamos l?

    O que voc precisa saber?Voc s conseguir absorver o contedo desse livro se j conhecer pelo menos obsico de SQL e Java e Orientao a Objetos. Caso voc ainda no domine Java eOO, pode ser interessante estudar por nosso curso online.

    Como obter ajuda?Durante os seus estudos, temos certeza de uma coisa: voc vai ter muitas dvidase problemas para resolver!

    Ns gostaramos muito de te ajudar pessoalmente nesses problemas e sanar todasas suas dvidas, mas infelizmente no conseguimos fazer isso com todos osleitores do livro, afinal, ocupamos grande parte do dia ajudando os nossos alunosde cursos online na AlgaWorks.

    Ento, quando voc tiver alguma dvida e no conseguir encontrar a soluo noGoogle ou com seu prprio conhecimento, nossa recomendao que voc posteno StackOverflow em portugus. s acessar:

    http://pt.stackoverflow.com/

    Para aumentar as chances de receber uma resposta para seu problema, vejaalgumas dicas:

    http://pt.stackoverflow.com/help/how-to-ask

    Ao perguntar sobre um problema no seu cdigo, voc conseguir melhoresrespostas se mostrar s pessoas cdigo que elas possam usar para reproduzir oproblema. Veja algumas recomendaes no link a seguir:

    http://pt.stackoverflow.com/help/mcve

  • Voc tambm pode ajudar outras pessoas com o conhecimento que adquiriu,assim todos sero ajudados de alguma forma.

    Comunidade Java da AlgaWorks no FacebookOutra forma de obter ajuda, contribuir com o seu conhecimento e manter contatocom outros programadores Java ingressando na ComunidadeComunidade JavaJava dadaAlgaWorksAlgaWorks (Facebook). Acesse:

    http://alga.works/comunidade-java-algaworks/

    Como sugerir melhorias ou reportar erros no livro?Se voc encontrar algum erro no contedo desse livro ou se tiver algumasugesto para melhorar a prxima edio, vamos ficar muito felizes se vocpuder nos dizer.

    Envie um e-mail para [email protected].

    Ajude na continuidade desse trabalhoEscrever um livro como esse d muito trabalho, por isso, esse projeto s fazsentido se muitas pessoas tiverem acesso a ele.

    Ajude a divulgar esse livro para seus amigos que tambm se interessam porprogramao Java. Compartilhe no Facebook e Twitter!

  • SumrioIntroduo

    O que persistncia? ................................................................................. 13

    Mapeamento Objeto Relacional (ORM) .................................................. 13

    Porque usar ORM? ..................................................................................... 15

    Java Persistence API e Hibernate ............................................................. 16

    Primeiros passos com JPA e HibernateDownload e configurao do Hibernate ORM ...................................... 17

    Criao do Domain Model ....................................................................... 19

    Implementao do equals() e hashCode() .............................................. 21

    Mapeamento bsico ................................................................................... 22

    O arquivo persistence.xml ........................................................................ 24

    Gerando as tabelas do banco de dados ................................................... 26

    Definindo detalhes fsicos de tabelas ...................................................... 27

    Criando EntityManager ............................................................................ 30

    Persistindo objetos ..................................................................................... 31

    Buscando objetos pelo identificador ....................................................... 34

    Listando objetos ......................................................................................... 36

    Atualizando objetos ................................................................................... 38

    Excluindo objetos ....................................................................................... 40

    Gerenciando estados

    11.1

    1.2

    1.3

    1.4

    22.1

    2.2

    2.3

    2.4

    2.5

    2.6

    2.7

    2.8

    2.9

    2.10

    2.11

    2.12

    2.13

    3

  • Estados e ciclo de vida .............................................................................. 42

    Contexto de persistncia ........................................................................... 44

    Sincronizao de dados ............................................................................. 46

    Salvando objetos desanexados com merge() ......................................... 49

    MapeamentoIdentificadores ............................................................................................ 52

    Chaves compostas ...................................................................................... 54

    Enumeraes ............................................................................................... 57

    Propriedades temporais ............................................................................ 58

    Propriedades transientes .......................................................................... 59

    Objetos grandes .......................................................................................... 60

    Objetos embutidos ..................................................................................... 64

    Associaes um-para-um .......................................................................... 67

    Associaes muitos-para-um ................................................................... 75

    Colees um-para-muitos ......................................................................... 77

    Colees muitos-para-muitos .................................................................. 79

    Colees de tipos bsicos e objetos embutidos ...................................... 85

    Herana ....................................................................................................... 90

    Modos de acesso ...................................................................................... 101

    Recursos avanadosLazy loading e eager loading ................................................................. 105

    Operaes em cascata .............................................................................. 113

    Excluso de objetos rfos ...................................................................... 117

    3.1

    3.2

    3.3

    3.4

    44.1

    4.2

    4.3

    4.4

    4.5

    4.6

    4.7

    4.8

    4.9

    4.10

    4.11

    4.12

    4.13

    4.14

    55.1

    5.2

    5.3

  • Operaes em lote .................................................................................... 118

    Concorrncia e locking ............................................................................ 121

    Mtodos de callback e auditores de entidades .................................... 125

    Cache de segundo nvel .......................................................................... 129

    Java Persistence Query LanguageIntroduo JPQL ................................................................................... 134

    Consultas simples e iterao no resultado ........................................... 140

    Usando parmetros nomeados .............................................................. 141

    Consultas tipadas ..................................................................................... 142

    Paginao .................................................................................................. 142

    Projees .................................................................................................... 144

    Resultados complexos e o operador new ............................................. 146

    Funes de agregao .............................................................................. 147

    Queries que retornam um resultado nico .......................................... 148

    Associaes e joins ................................................................................... 149

    Queries nomeadas ................................................................................... 154

    Queries SQL nativas ................................................................................ 156

    Criteria APIIntroduo e estrutura bsica ................................................................. 158

    Filtros e queries dinmicas ..................................................................... 159

    Projees .................................................................................................... 162

    Funes de agregao .............................................................................. 162

    Resultados complexos, tuplas e construtores ...................................... 163

    5.4

    5.5

    5.6

    5.7

    66.1

    6.2

    6.3

    6.4

    6.5

    6.6

    6.7

    6.8

    6.9

    6.10

    6.11

    6.12

    77.1

    7.2

    7.3

    7.4

    7.5

  • Funes ...................................................................................................... 165

    Ordenao de resultado .......................................................................... 166

    Join e fetch ................................................................................................. 167

    Subqueries ................................................................................................. 168

    Metamodel ................................................................................................ 170

    ConclusoPrximos passos ....................................................................................... 172

    7.6

    7.7

    7.8

    7.9

    7.10

    88.1

  • Captulo 1

    Introduo

    1.1. O que persistncia?

    A maioria dos sistemas desenvolvidos em uma empresa precisa de dadospersistentes, portanto persistncia um conceito fundamental nodesenvolvimento de aplicaes. Se um sistema de informao no preservasse osdados quando ele fosse encerrado, o sistema no seria prtico e usual.

    Quando falamos de persistncia de dados com Java, normalmente falamos douso de sistemas gerenciadores de banco de dados relacionais e SQL, pormexistem diversas outras alternativas para persistir dados, como em arquivosXML, arquivos texto e etc.

    1.2. Mapeamento Objeto Relacional (ORM)

    Mapeamento objeto relacional (object-relational mapping, ORM, O/RM ou O/Rmapping) uma tcnica de programao para converso de dados entre bancode dados relacionais e linguagens de programao orientada a objetos.

    Em banco de dados, entidades so representadas por tabelas, que possuemcolunas que armazenam propriedades de diversos tipos. Uma tabela pode seassociar com outras e criar relacionamentos diversos.

    www.algaworks.com 13

  • Em uma linguagem orientada a objetos, como Java, entidades so classes, eobjetos dessas classes representam elementos que existem no mundo real.

    Por exemplo, um sistema de faturamento possui a classe NotaFiscal, que nomundo real existe e todo mundo j viu alguma pelo menos uma vez, alm depossuir uma classe que pode se chamar Imposto. Essas classes so chamadasde classes de domnio do sistema, pois fazem parte do negcio que est sendodesenvolvido.

    Em banco de dados, podemos ter as tabelas nota_fiscal e tambm imposto, masa estrutura de banco de dados relacional est longe de ser orientado a objetos, epor isso a ORM foi inventada para suprir a necessidade que os desenvolvedorestm de visualizar tudo como objetos para programarem com mais facilidade.

    Podemos comparar o modelo relacional com o modelo orientado a objetosconforme a tabela abaixo:

    Modelo relacionalModelo relacional Modelo OOModelo OO

    Tabela Classe

    Linha Objeto

    Coluna Atributo

    - Mtodo

    Chave estrangeira Associao

    Essa comparao feita em todo o tempo quando estamos desenvolvendousando algum mecanismo de ORM. O mapeamento feito usando metadadosque descrevem a relao entre objetos e banco de dados.

    Uma soluo ORM consiste de uma API para executar operaes CRUD simplesem objetos de classes persistentes, uma linguagem ou API para especificarqueries que se referem a classes e propriedades de classes, facilidades paraespecificar metadados de mapeamento e tcnicas para interagir com objetos

    www.algaworks.com 14

  • transacionais para identificarem automaticamente alteraes realizadas,carregamento de associaes por demanda e outras funes de otimizao.

    Em um ambiente ORM, as aplicaes interagem com APIs e o modelo de classesde domnio e os cdigos SQL/JDBC so abstrados. Os comandos SQL soautomaticamente gerados a partir dos metadados que relacionam objetos a bancode dados.

    1.3. Porque usar ORM?

    Apesar de no parecer, uma implementao ORM mais complexa que outroframework qualquer para desenvolvimento web, porm os benefcios dedesenvolver utilizando esta tecnologia so grandes.

    Cdigos de acesso a banco de dados com queries SQL so chatos de escrever.JPA elimina muito do trabalho e deixa voc se concentrar na lgica de negcio,possibilitando uma produtividade imensa para voc.

    A manutenabilidade de sistemas desenvolvidos com ORM excelente, pois omecanismo faz com que menos linhas de cdigo sejam necessrias. Alm defacilitar o entendimento, menos linhas de cdigo deixam o sistema mais fcil deser alterado.

    Existem outras razes que fazem com que um sistema desenvolvido utilizandoJPA seja melhor de ser mantido. Em sistemas com a camada de persistnciadesenvolvida usando JDBC e SQL, existe um trabalho na implementao pararepresentar tabelas como objetos de domnio, e alteraes no banco de dados ouno modelo de domnio geram um esforo de readequao que pode custar caro.

    ORM abstrai sua aplicao do banco de dados e do dialeto SQL. Com JPA,voc pode desenvolver um sistema usando um banco de dados e coloc-lo emproduo usando diversos outros bancos de dados, sem precisar alterar cdigos-fontes para adequar sintaxe de queries que s funcionam em SGBDs dedeterminados fornecedores.

    www.algaworks.com 15

  • 1.4. Java Persistence API e Hibernate

    A Java Persistence API (JPA) um framework para persistncia em Java, queoferece uma API de mapeamento objeto-relacional e solues para integrarpersistncia com sistemas corporativos escalveis.

    Com JPA, os objetos so POJO (Plain Old Java Objects), ou seja, no necessrionada de especial para tornar os objetos persistentes. Basta adicionar algumasanotaes nas classes que representam as entidades do sistema e comear apersistir ou consultar objetos.

    JPA uma especificao, e no um produto. Para trabalhar com JPA, precisamosde uma implementao.

    O projeto do Hibernate ORM possui alguns mdulos, sendo que o HibernateHibernateEntityManagerEntityManager a implementao da JPA que encapsula o Hibernate Core.

    O HibernateHibernate CoreCore a base para o funcionamento da persistncia, com APIsnativas e metadados de mapeamentos em arquivos XML, uma linguagem deconsultas chamada HQL (parecido com SQL), um conjunto de interfaces paraconsultas usando critrios (Criteria API), etc.

    www.algaworks.com 16

  • Captulo 2

    Primeiros passos com JPA eHibernate

    2.1. Download e configurao do Hibernate ORM

    Antes de criarmos um projeto, precisamos fazer o download do Hibernate ORMno site www.hibernate.org. O arquivo fornecido no site possui todos os mdulose dependncias necessrias.

    www.algaworks.com 17

  • Depois de concluir o download, descompacte o arquivo em um diretriotemporrio.

    Crie um novo projeto no Eclipse do tipo Java Project e crie uma pasta dentrodele chamada lib, para que possamos colocar os JARs necessrios.

    Copie todos os arquivos das pastas required e jpa para a pasta lib doprojeto.

    Estas bibliotecas que voc acabou de copiar fazem parte da distribuio doHibernate ORM e so obrigatrias para seu funcionamento. As demais sorequeridas apenas para casos especficos.

    Como usaremos o MySQL neste livro, precisaremos colocar tambm o driverJDBC do MySQL na pasta lib. Baixe em http://dev.mysql.com/downloads/connector/j/.

    Agora que temos todas as bibliotecas necessrias na pasta lib do projeto,precisamos adicon-las ao Build Path do projeto. Encontre e selecione todos osarquivos JAR que esto dentro do seu projeto no Eclipse, clique com o botodireito, acesse a opo Build Path e Add to Build Path.

    Seu projeto deve ficar com as seguintes bibliotecas referenciadas:

    www.algaworks.com 18

  • 2.2. Criao do Domain Model

    Em nosso projeto de exemplo, queremos gravar e consultar informaes deveculos de uma concessionria no banco de dados. Antes de qualquer coisa,precisamos criar nosso modelo de domnio para o negcio em questo.

    Inicialmente, nosso sistema possuir uma classe simples chamada Veiculo, querepresenta o veculo venda pela concessionria.

    package com.algaworks.veiculos.dominio;

    import java.math.BigDecimal;

    public class Veiculo {

    private Long codigo;private String fabricante;private String modelo;private Integer anoFabricacao;private Integer anoModelo;private BigDecimal valor;

    public Long getCodigo() {return codigo;

    }

    public void setCodigo(Long codigo) {this.codigo = codigo;

    }

    public String getFabricante() {return fabricante;

    }

    public void setFabricante(String fabricante) {this.fabricante = fabricante;

    }

    public String getModelo() {return modelo;

    }

    www.algaworks.com 19

  • public void setModelo(String modelo) {this.modelo = modelo;

    }

    public Integer getAnoFabricacao() {return anoFabricacao;

    }

    public void setAnoFabricacao(Integer anoFabricacao) {this.anoFabricacao = anoFabricacao;

    }

    public Integer getAnoModelo() {return anoModelo;

    }

    public void setAnoModelo(Integer anoModelo) {this.anoModelo = anoModelo;

    }

    public BigDecimal getValor() {return valor;

    }

    public void setValor(BigDecimal valor) {this.valor = valor;

    }

    }

    A classe Veiculo possui os seguintes atributos:

    codigo: identificador nico do veculo fabricante: nome do fabricante do veculo modelo: descrio do modelo do veculo anoFabricacao: nmero do ano de fabricao do veculo anoModelo: nmero do ano do modelo do veculo valor: valor que est sendo pedido para venda do veculo

    O atributo identificador (chamado de codigo) referente chave primria databela de veculos no banco de dados. Se existirem duas instncias de Veiculocom o mesmo identificador, eles representam a mesma linha no banco de dados.

    www.algaworks.com 20

  • As classes persistentes devem seguir o estilo de JavaBeans, com mtodos getters esetters. obrigatrio que esta classe possua um construtor sem argumentos.

    Como voc pode ver, a classe persistente Veiculo um POJO, o que significa quepodemos instanci-la sem necessidade de containeres especiais.

    Observao:Observao: nas sees e captulos seguintes, podemos desenvolver novosexemplos para o projeto da concessionria, sem acumular todos os recursosestudados, para no dificultar o entendimento de cada um desses recursos.

    2.3. Implementao do equals() e hashCode()

    Para que os objetos persistentes sejam diferenciados uns de outros, precisamosimplementar os mtodos equals() e hashCode().

    No banco de dados, as chaves primrias diferenciam registros distintos. Quandomapeamos uma entidade de uma tabela, devemos criar os mtodos equals()e hashCode(), levando em considerao a forma em que os registros sodiferenciados no banco de dados.

    O Eclipse possui um gerador desses mtodos que usa uma propriedade (ouvrias, informadas por voc) para criar o cdigo-fonte. Veja como deve ficar aimplementao dos mtodos para a entidade Veiculo.

    @Overridepublic int hashCode() {

    final int prime = 31;int result = 1;result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());return result;

    }

    @Overridepublic boolean equals(Object obj) {

    if (this == obj)return true;

    if (obj == null)return false;

    if (getClass() != obj.getClass())

    www.algaworks.com 21

  • return false;final Veiculo other = (Veiculo) obj;if (codigo == null) {

    if (other.codigo != null)return false;

    } else if (!codigo.equals(other.codigo))return false;

    return true;}

    Agora o Hibernate conseguir comparar objetos para descobrir se so os mesmos.

    Qual a real importncia dos mtodosQual a real importncia dos mtodos equals ee hashCode??

    Entender os motivos por trs da implementao desses mtodos muitoimportante. Assista uma vdeo aula gratuita sobre esse assunto no nossoblog.

    http://blog.algaworks.com/entendendo-o-equals-e-hashcode/

    2.4. Mapeamento bsico

    Para que o mapeamento objeto/relacional funcione, precisamos informar implementao do JPA mais informaes sobre como a classe Veiculo deve setornar persistente, ou seja, como instncias dessa classe podem ser gravadase consultadas no banco de dados. Para isso, devemos anotar os getters ou osatributos, alm da prpria classe.

    import java.math.BigDecimal;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;

    @Entitypublic class Veiculo {

    www.algaworks.com 22

  • private Long codigo;private String fabricante;private String modelo;private Integer anoFabricacao;private Integer anoModelo;private BigDecimal valor;

    @Id@GeneratedValuepublic Long getCodigo() {

    return codigo;}

    public void setCodigo(Long codigo) {this.codigo = codigo;

    }

    public String getFabricante() {return fabricante;

    }

    public void setFabricante(String fabricante) {this.fabricante = fabricante;

    }

    public String getModelo() {return modelo;

    }

    public void setModelo(String modelo) {this.modelo = modelo;

    }

    public Integer getAnoFabricacao() {return anoFabricacao;

    }

    public void setAnoFabricacao(Integer anoFabricacao) {this.anoFabricacao = anoFabricacao;

    }

    public Integer getAnoModelo() {return anoModelo;

    www.algaworks.com 23

  • }public void setAnoModelo(Integer anoModelo) {this.anoModelo = anoModelo;

    }

    public BigDecimal getValor() {return valor;

    }

    public void setValor(BigDecimal valor) {this.valor = valor;

    }

    // equals e hashCode

    }

    Voc deve ter percebido que as anotaes foram importadas do pacotejavax.persistence. Dentro desse pacote esto todas as anotaes padronizadaspela JPA.

    A anotao @Entity diz que a classe uma entidade, que representa uma tabelado banco de dados.

    As anotaes nos mtodos getters configuram a relao dos atributos da classecom as colunas do banco de dados. As anotaes @Id e @GeneratedValue sousadas para declarar o identificador do banco de dados, e esse identificador deveter um valor gerado no momento de insero (auto-incremento).

    2.5. O arquivo persistence.xml

    O persistence.xml um arquivo de configurao padro da JPA. Ele deve sercriado no diretrio META-INF da aplicao ou do mdulo que contm os beansde entidade.

    O arquivo persistence.xml define unidades de persistncia, conhecidas comopersistence units.

    www.algaworks.com 24

  • org.hibernate.ejb.HibernatePersistence

    O nome da unidade de persistncia foi definido como AlgaWorksPU. Precisaremosdesse nome daqui a pouco, quando formos colocar tudo para funcionar.

    O provider diz qual a implementao que ser usada como provedor depersistncia.

    Existem vrias opes de configurao que podem ser informadas neste arquivoXML. Vejamos as principais propriedades que usamos em nosso arquivo deconfigurao:

    javax.persistence.jdbc.url: descrio da URL de conexo com o bancode dados

    www.algaworks.com 25

  • javax.persistence.jdbc.driver: nome completo da classe do driverJDBC

    javax.persistence.jdbc.user: nome do usurio do banco de dados javax.persistence.jdbc.password: senha do usurio do banco de dados hibernate.dialect: dialeto a ser usado na construo de comandos SQL hibernate.show_sql: informa se os comandos SQL devem ser exibidos na

    console (importante para debug, mas deve ser desabilitado em ambientede produo)

    hibernate.format_sql: indica se os comandos SQL exibidos na consoledevem ser formatados (facilita a compreenso, mas pode gerar textoslongos na sada)

    hibernate.hbm2ddl.auto: cria ou atualiza automaticamente a estruturadas tabelas no banco de dados

    2.6. Gerando as tabelas do banco de dados

    Como ainda no temos a tabela representada pela classe Veiculo no banco dedados, precisamos cri-la.

    O Hibernate pode fazer isso pra gente, graas propriedadehibernate.hbm2ddl.auto com valor update, que inclumos no arquivopersistence.xml.

    Precisamos apenas criar um EntityManagerFactory, que todas as tabelasmapeadas pelas entidades sero criadas ou atualizadas.

    import javax.persistence.Persistence;

    public class CriaTabelas {

    public static void main(String[] args) {Persistence.createEntityManagerFactory("AlgaWorksPU");

    }

    }

    www.algaworks.com 26

  • O parmetro do mtodo createEntityManagerFactory deve ser o mesmo nomeque informamos no atributo name da tag persistence-unit, no arquivopersistence.xml.

    Ao executar o cdigo, a tabela Veiculo criada.

    ...Jul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.SchemaUpdate executeINFO: HHH000228: Running hbm2ddl schema updateJul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.SchemaUpdate executeINFO: HHH000102: Fetching database metadataJul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.SchemaUpdate executeINFO: HHH000396: Updating schemaJul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.DatabaseMetadata [...]INFO: HHH000262: Table not found: VeiculoJul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.DatabaseMetadata [...]INFO: HHH000262: Table not found: VeiculoJul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.DatabaseMetadata [...]INFO: HHH000262: Table not found: VeiculoJul 11, 2015 1:27:19 AM org.hibernate.tool.hbm2ddl.SchemaUpdate executeINFO: HHH000232: Schema update complete

    2.7. Definindo detalhes fsicos de tabelas

    A estrutura da tabela que foi criada no banco de dados bastante simples.Veja que todas as propriedades com getters foram mapeadas automaticamente,mesmo sem incluir qualquer anotao JPA.

    Com exceo da chave primria, todas as colunas aceitam valores nulos e ascolunas fabricante e modelo aceitam at 255 caracteres.

    www.algaworks.com 27

  • Podemos definir melhor estes detalhes fsicos no mapeamento de nossa entidade.

    Alm disso, queremos que nomes de colunas usem underscore na separao depalavras, que o nome da tabela seja tab_veiculo e a preciso da coluna valor seja10, com 2 casas decimais.

    import java.math.BigDecimal;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Table;

    @Entity@Table(name = "tab_veiculo")public class Veiculo {

    private Long codigo;private String fabricante;private String modelo;private Integer anoFabricacao;private Integer anoModelo;private BigDecimal valor;

    @Id@GeneratedValuepublic Long getCodigo() {

    return codigo;}

    public void setCodigo(Long codigo) {this.codigo = codigo;

    }

    @Column(length = 60, nullable = false)public String getFabricante() {

    return fabricante;}

    public void setFabricante(String fabricante) {this.fabricante = fabricante;

    }

    www.algaworks.com 28

  • @Column(length = 60, nullable = false)public String getModelo() {

    return modelo;}

    public void setModelo(String modelo) {this.modelo = modelo;

    }

    @Column(name = "ano_fabricacao", nullable = false)public Integer getAnoFabricacao() {

    return anoFabricacao;}

    public void setAnoFabricacao(Integer anoFabricacao) {this.anoFabricacao = anoFabricacao;

    }

    @Column(name = "ano_modelo", nullable = false)public Integer getAnoModelo() {

    return anoModelo;}

    public void setAnoModelo(Integer anoModelo) {this.anoModelo = anoModelo;

    }

    @Column(precision = 10, scale = 2, nullable = true)public BigDecimal getValor() {

    return valor;}

    public void setValor(BigDecimal valor) {this.valor = valor;

    }

    // equals e hashCode

    }

    Podemos executar o cdigo main anterior, que cria um EntityManagerFactory, e anova tabela ser gerada.

    www.algaworks.com 29

  • A tabela antiga, chamada Veiculo, no ser excluda. Voc precisar fazer isso namo, se quiser elimin-la.

    Agora, vamos analisar as alteraes que fizemos individualmente.

    @Table(name = "tab_veiculo")public class Veiculo {

    Especificamos o nome da tabela como tab_veiculo. Se no fizermos isso, o nomeda tabela ser considerado o mesmo nome da classe.

    @Column(length = 60, nullable = false)public String getFabricante() {

    Definimos o tamanho da coluna com 60 e com restrio not null.

    @Column(name = "ano_fabricacao", nullable = false)public Integer getAnoFabricacao() {

    Especificamos o nome da coluna como ano_fabricacao e com restrio not null. Seo nome da coluna no for especificado, por padro, ela receber o mesmo nomedo atributo mapeado.

    @Column(precision = 10, scale = 2, nullable = true)public BigDecimal getValor() {

    Atribumos a preciso de 10 com escala de 2 casas na coluna de nmero decimal,especificando, ainda, que ela pode receber valores nulos.

    2.8. Criando EntityManager

    Os sistemas que usam JPA precisam de apenas uma instncia deEntityManagerFactory, que pode ser criada durante a inicializao da aplicao.Esta nica instncia pode ser usada por qualquer cdigo que queira obter umEntityManager.

    Um EntityManager responsvel por gerenciar entidades no contexto depersistncia (que voc aprender mais a frente). Atravs dos mtodos dessainterface, possvel persistir, pesquisar e excluir objetos do banco de dados.

    www.algaworks.com 30

  • A inicializao de EntityManagerFactory pode demorar alguns segundos, por issoa instncia dessa interface deve ser compartilhada na aplicao.

    Precisaremos de um lugar para colocar a instncia compartilhada deEntityManagerFactory, onde qualquer cdigo tenha acesso fcil e rpido.Criaremos a classe JpaUtil para armazenar a instncia em uma varivel esttica.

    import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import javax.persistence.Persistence;

    public class JpaUtil {

    private static EntityManagerFactory factory;

    static {factory = Persistence.createEntityManagerFactory("AlgaWorksPU");

    }

    public static EntityManager getEntityManager() {return factory.createEntityManager();

    }

    public static void close() {factory.close();

    }

    }

    Criamos um bloco esttico para inicializar a fbrica de Entity Manager. Issoocorrer apenas uma vez, no carregamento da classe. Agora, sempre queprecisarmos de uma EntityManager, podemos chamar:

    EntityManager manager = JpaUtil.getEntityManager();

    2.9. Persistindo objetos

    Chegou a hora de persistir objetos, ou seja, inserir registros no banco de dados.

    www.algaworks.com 31

  • O cdigo abaixo deve inserir um novo veculo na tabela do banco de dados. Seno funcionar, no se desespere, volte nos passos anteriores e encontre o que vocfez de errado.

    import javax.persistence.EntityManager;import javax.persistence.EntityTransaction;

    public class PersistindoVeiculo {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("Honda");veiculo.setModelo("Civic");veiculo.setAnoFabricacao(2012);veiculo.setAnoModelo(2013);veiculo.setValor(new BigDecimal(71300));

    manager.persist(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    }

    }

    Execute a classe InsercaoVeiculos e veja a sada no console.

    Hibernate:insertinto

    tab_veiculo(ano_fabricacao, ano_modelo, fabricante, modelo, valor)

    values(?, ?, ?, ?, ?)

    O Hibernate gerou o SQL de insero e nos mostrou na sada, pois configuramosisso no arquivo persistence.xml.

    www.algaworks.com 32

  • Consulte os dados da tabela tab_veiculo usando qualquer ferramenta degerenciamento do seu banco de dados e veja que as informaes que definimosnos atributos da instncia do veculo, atravs de mtodos setters, foramarmazenadas.

    Agora vamos entender o que cada linha significa.

    O cdigo abaixo obtm um EntityManager da classe JpaUtil.

    EntityManager manager = JpaUtil.getEntityManager();

    Agora iniciamos uma nova transao.

    EntityTransaction tx = manager.getTransaction();tx.begin();

    Instanciamos um novo veculo e atribumos alguns valores, chamando osmtodos setters.

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("Honda");veiculo.setModelo("Civic");veiculo.setAnoFabricacao(2012);veiculo.setAnoModelo(2013);veiculo.setValor(new BigDecimal(71300));

    Executamos o mtodo persist, passando o veculo como parmetro. Isso farcom que o JPA insira o objeto no banco de dados. No informamos o cdigodo veculo, porque ele ser obtido automaticamente atravs do auto-increment doMySQL.

    manager.persist(veiculo);

    Agora fazemos commit da transao, para efetivar a insero do veculo no bancode dados.

    tx.commit();

    www.algaworks.com 33

  • Finalmente, fechamos o EntityManager e o EntityManagerFactory.

    manager.close();JpaUtil.close();

    Viu? Nenhum cdigo SQL e JDBC! Trabalhamos apenas com classes, objetos e aAPI de JPA.

    2.10. Buscando objetos pelo identificador

    Podemos recuperar objetos atravs do identificador (chave primria) daentidade. O cdigo abaixo busca um veculo com o cdigo igual a 1.

    public class BuscandoVeiculo1 {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo = manager.find(Veiculo.class, 1L);

    System.out.println("Veculo de cdigo " + veiculo.getCodigo()+ " um " + veiculo.getModelo());

    manager.close();JpaUtil.close();

    }

    }

    O resultado na console o seguinte:

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    www.algaworks.com 34

  • whereveiculo0_.codigo=?

    Veculo de cdigo 1 um Civic

    Veja que o SQL gerado possui a clusula where, para filtrar apenas o veculo decdigo igual a 1.

    Podemos tambm buscar um objeto pelo identificador usando o mtodogetReference.

    public class BuscandoVeiculo2 {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo = manager.getReference(Veiculo.class, 1L);System.out.println("Veculo de cdigo " + veiculo.getCodigo()

    + " um " + veiculo.getModelo());

    manager.close();JpaUtil.close();

    }

    }

    O resultado na console o mesmo, deixando a impresso que os mtodos finde getReference fazem a mesma coisa, mas na verdade, esses mtodos possuemcomportamentos um pouco diferentes.

    O mtodo find busca o objeto imediatamente no banco de dados, enquantogetReference s executa o SQL quando o primeiro mtodo getter for chamado,desde que no seja o getCodigo.

    Veja esse exemplo:

    public class BuscandoVeiculo3 {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo = manager.getReference(Veiculo.class, 1L);System.out.println("Buscou veculo. Ser que j executou o SELECT?");

    www.algaworks.com 35

  • System.out.println("Veculo de cdigo " + veiculo.getCodigo()+ " um " + veiculo.getModelo());

    manager.close();JpaUtil.close();

    }

    }

    A execuo do cdigo exibe na sada:

    Buscou veculo. Ser que j executou o SELECT?Hibernate:

    selectveiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Veculo de cdigo 1 um Civic

    Note que o SQL foi executado apenas quando um getter foi invocado, e no nachamada de getReference.

    2.11. Listando objetos

    Agora, voc ir aprender como fazer consultas simples de entidades com alinguagem JPQL (Java Persistence Query Language). Aprofundaremos um poucomais nessa linguagem em outro captulo, porm j usaremos o bsico paraconseguirmos consultar no banco de dados.

    A JPQL uma extenso da SQL, porm com caractersticas da orientao aobjetos. Com essa linguagem, no referenciamos tabelas do banco de dados, masapenas entidades de nosso modelo, que foram mapeadas para tabelas.

    www.algaworks.com 36

  • Quando fazemos pesquisas em objetos, no precisamos selecionar as colunas dobanco de dados, como o caso da SQL. O cdigo em SQL a seguir:

    select * from veiculo

    Fica da seguinte forma em JPQL:

    from Veiculo

    A sintaxe acima em JPQL significa que queremos buscar os objetos persistentesda classe Veiculo.

    Antes de ver como fica no cdigo Java, insira outros veculos na tabela para queos testes fiquem mais interessantes.

    import java.util.List;import javax.persistence.EntityManager;import javax.persistence.Query;

    public class ListandoVeiculos {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();

    Query query = manager.createQuery("from Veiculo");List veiculos = query.getResultList();

    for (Veiculo veiculo : veiculos) {System.out.println(veiculo.getCodigo() + " - "

    + veiculo.getFabricante() + " "+ veiculo.getModelo() + ", ano "+ veiculo.getAnoFabricacao() + "/"+ veiculo.getAnoModelo() + " por "+ "R$" + veiculo.getValor());

    }

    manager.close();JpaUtil.close();

    }

    }

    O resultado na console foi o seguinte:

    www.algaworks.com 37

  • Hibernate:select

    veiculo0_.codigo as codigo1_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_,veiculo0_.ano_modelo as ano_mode3_0_,veiculo0_.fabricante as fabrican4_0_,veiculo0_.modelo as modelo5_0_,veiculo0_.valor as valor6_0_

    fromtab_veiculo veiculo0_

    1 - Honda Civic, ano 2012/2013 por R$71300.002 - GM Corsa Sedan, ano 2005/2005 por R$16500.003 - VW Gol, ano 2009/2009 por R$21000.00

    A consulta SQL foi gerada baseada nas informaes do mapeamento, e todos osveculos da tabela foram listados.

    A nica novidade no cdigo-fonte que usamos so as seguintes linhas:

    Query query = manager.createQuery("from Veiculo");List veiculos = query.getResultList();

    Veja que criamos uma query com a JPQL e armazenamos em uma varivel query.Depois, executamos o mtodo getResultList desse objeto e obtemos uma lista deveculos.

    As IDEs, como o Eclipse, podem mostrar um alerta de Type safety emquery.getResultList(). Por enquanto voc pode ignorar isso, porque em brevevoc vai aprender sobre TypedQuery.

    2.12. Atualizando objetos

    Os atributos de entidades podem ser manipulados atravs dos mtodos setters,e todas as alteraes sero detectadas e persistidas automaticamente, quando ocontexto de persistncia for descarregado para o banco de dados.

    Vamos a um exemplo:

    www.algaworks.com 38

  • public class AtualizandoVeiculo {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = manager.find(Veiculo.class, 1L);

    System.out.println("Valor atual: " + veiculo.getValor());veiculo.setValor(veiculo.getValor().add(new BigDecimal(500)));System.out.println("Novo valor: " + veiculo.getValor());

    tx.commit();manager.close();JpaUtil.close();

    }

    }

    O cdigo acima executa o comando select no banco de dados para buscar oveculo de cdigo 1, imprime o valor atual do veculo, atribui um novo valor(soma 500,00 reais) e imprime um novo valor.

    Veja que no precisamos chamar nenhum mtodo para a atualizao no bancode dados. A alterao foi identificada automaticamente e refletida no banco dedados, atravs do comando update.

    A sada abaixo foi apresentada na console:

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    www.algaworks.com 39

  • Valor atual: 71300.00Novo valor: 71800.00Hibernate:

    updatetab_veiculo

    setano_fabricacao=?,ano_modelo=?,fabricante=?,modelo=?,valor=?

    wherecodigo=?

    2.13. Excluindo objetos

    A excluso de objetos feita chamando o mtodo remove de EntityManager,passando como parmetro o objeto.

    public class ExcluindoVeiculo {

    public static void main(String[] args) {EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = manager.find(Veiculo.class, 1L);

    manager.remove(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    }

    }

    O resultado na console o seguinte:

    Hibernate:select

    www.algaworks.com 40

  • veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Hibernate:deletefrom

    tab_veiculowhere

    codigo=?

    www.algaworks.com 41

  • Captulo 3

    Gerenciando estados

    3.1. Estados e ciclo de vida

    Objetos de entidades so instncias de classes mapeadas usando JPA, que ficamna memria e representam registros do banco de dados. Essas instnciaspossuem um ciclo de vida, que gerenciado pelo JPA.

    Os estados do ciclo de vida das entidades so: transient (ou new), managed,detached e removed.

    As transies entre os estados so feitas atravs de mtodos do EntityManager.Vamos aprender o que significa cada estado do ciclo de vida dos objetos.

    www.algaworks.com 42

  • Objetos transientes

    Objetos transientes (transient) so instanciados usando o operador new. Issosignifica que eles ainda no esto associados com um registro na tabela do bancode dados, e podem ser perdidos e coletados pelo garbage collector quando noestiver mais sendo usado.

    Objetos gerenciados

    Objetos gerenciados (managed) so instncias de entidades que possuem umidentificador e representam um registro da tabela do banco de dados.

    As instncias gerenciadas podem ser objetos que foram persistidos atravs dachamada de um mtodo do EntityManager, como por exemplo o persist. Elestambm podem ter se tornado gerenciados atravs de mtodos de consulta doEntityManager, que buscam registros da base de dados e instanciam objetosdiretamente no estado managed.

    Objetos gerenciados esto sempre associados a um contexto de persistncia,portanto, quaisquer alteraes nesses objetos so sincronizadas com o banco dedados.

    Objetos removidos

    Uma instncia de uma entidade pode ser excluda atravs do mtodo remove doEntityManager.

    Um objeto entra no estado removed quando ele marcado para ser eliminado, mas fisicamente excludo durante a sincronizao com o banco de dados.

    Objetos desanexados

    Um objeto sempre inicia no estado transiente e depois pode se tornar gerenciado.Quando o Entity Manager fechado, continua existindo uma instncia do objeto,mas j no estado detached.

    www.algaworks.com 43

  • Esse estado existe para quando os objetos esto desconectados, no tendo maissincronia com o banco de dados. A JPA fornece operaes para reconectar essesobjetos a um novo EntityManager, que veremos adiante.

    3.2. Contexto de persistncia

    O contexto de persistncia uma coleo de objetos gerenciados por umEntityManager.

    Se uma entidade pesquisada, mas ela j existe no contexto de persistncia,o objeto existente retornado, sem acessar o banco de dados. Esse recurso chamado de cache de primeiro nvelcache de primeiro nvel.

    Uma mesma entidade pode ser representada por diferentes objetos na memria,desde que seja em diferentes instncias de EntityManagers. Em uma nicainstncia de EntityManager, apenas um objeto que representa determinadaentidade (com o mesmo identificador) pode ser gerenciada.

    EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo1 = manager.find(Veiculo.class, 2L);System.out.println("Buscou veiculo pela primeira vez...");

    Veiculo veiculo2 = manager.find(Veiculo.class, 2L);System.out.println("Buscou veiculo pela segunda vez...");

    System.out.println("Mesmo veculo? " + (veiculo1 == veiculo2));

    manager.close();JpaUtil.close();

    O cdigo acima busca o mesmo veculo duas vezes, dentro do mesmo contextode persistncia. A consulta SQL foi executada apenas na primeira vez, pois nasegunda, o objeto j estava no cache de primeiro nvel. Veja a sada:

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,

    www.algaworks.com 44

  • veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Buscou veiculo pela primeira vez...Buscou veiculo pela segunda vez...Mesmo veculo? true

    O mtodo contains de EntityManager verifica se o objeto est sendo gerenciadopelo contexto de persistncia do EntityManager. O mtodo detach pra degerenciar a entidade no contexto de persistncia, colocando ela no estadodetached.

    EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo1 = manager.find(Veiculo.class, 2L);System.out.println("Buscou veiculo pela primeira vez...");

    System.out.println("Gerenciado? " + manager.contains(veiculo1));manager.detach(veiculo1);System.out.println("E agora? " + manager.contains(veiculo1));

    Veiculo veiculo2 = manager.find(Veiculo.class, 2L);System.out.println("Buscou veiculo pela segunda vez...");

    System.out.println("Mesmo veculo? " + (veiculo1 == veiculo2));

    manager.close();JpaUtil.close();

    A execuo do cdigo acima imprime na sada:

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,

    www.algaworks.com 45

  • veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Buscou veiculo pela primeira vez...Gerenciado? trueE agora? falseHibernate:

    selectveiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Buscou veiculo pela segunda vez...Mesmo veculo? false

    Veja que agora a consulta foi executada duas vezes, pois desanexamos o veculoque estava sendo gerenciado pelo contexto de persistncia.

    3.3. Sincronizao de dados

    Os estados de entidades so sincronizados com o banco de dados quando ocorreo commit da transao associada.

    Vamos usar um exemplo anterior, para entender melhor.

    EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = manager.find(Veiculo.class, 2L);

    www.algaworks.com 46

  • System.out.println("Valor atual: " + veiculo.getValor());veiculo.setValor(veiculo.getValor().add(new BigDecimal(500)));

    System.out.println("Novo valor: " + veiculo.getValor());

    tx.commit();manager.close();JpaUtil.close();

    Veja na sada abaixo que o comando update foi executado apenas no final daexecuo, exatamente durante o commit da transao.

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Valor atual: 16500.00Novo valor: 17000.00Hibernate:

    updatetab_veiculo

    setano_fabricacao=?,ano_modelo=?,fabricante=?,modelo=?,valor=?

    wherecodigo=?

    Podemos forar a sincronizao antes mesmo do commit, chamando o mtodoflush de EntityManager.

    www.algaworks.com 47

  • EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = manager.find(Veiculo.class, 2L);

    System.out.println("Valor atual: " + veiculo.getValor());veiculo.setValor(veiculo.getValor().add(new BigDecimal(500)));

    manager.flush();

    System.out.println("Novo valor: " + veiculo.getValor());

    tx.commit();manager.close();JpaUtil.close();

    Agora, o comando update foi executado antes do ltimo print que fizemos, queexibe o novo valor.

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Valor atual: 17000.00Hibernate:

    updatetab_veiculo

    setano_fabricacao=?,ano_modelo=?,fabricante=?,modelo=?,valor=?

    where

    www.algaworks.com 48

  • codigo=?Novo valor: 17500.00

    3.4. Salvando objetos desanexados com merge()

    Objetos desanexados so objetos em um estado que no gerenciado peloEntityManager, mas ainda representa uma entidade no banco de dados. Asalteraes em objetos desanexados no so sincronizadas com o banco de dados.

    Quando estamos desenvolvendo sistemas, existem diversos momentos quesomos obrigados a trabalhar com objetos desanexados, por exemplo, quando elesso expostos para alterao atravs de pginas web e apenas em um segundomomento o usurio solicita a gravao das alteraes do objeto.

    No cdigo abaixo, alteramos o valor de um veculo em um momento que o objetoest no estado detached, por isso, a modificao no sincronizada.

    EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = manager.find(Veiculo.class, 2L);

    tx.commit();manager.close();

    // essa alterao no ser sincronizadaveiculo.setValor(new BigDecimal(5_000));

    JpaUtil.close();

    Podemos reanexar objetos em qualquer EntityManager usando o mtodo merge.

    EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = manager.find(Veiculo.class, 2L);

    tx.commit();

    www.algaworks.com 49

  • manager.close();

    veiculo.setValor(new BigDecimal(5_000));

    manager = JpaUtil.getEntityManager();tx = manager.getTransaction();tx.begin();

    // reanexamos o objeto ao novo EntityManagerveiculo = manager.merge(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    O contedo do objeto desanexado copiado para um objeto gerenciado com amesma identidade. Se o EntityManager ainda no estiver gerenciando um objetocom a mesma identidade, ser realizada uma consulta para encontr-lo, ou ainda,ser persistida uma nova entidade.

    O retorno do mtodo merge uma instncia de um objeto gerenciado. O objetodesanexado no muda de estado, ou seja, continua detached.

    A execuo do cdigo acima exibe na sada:

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Hibernate:select

    veiculo0_.codigo as codigo1_0_0_,veiculo0_.ano_fabricacao as ano_fabr2_0_0_,veiculo0_.ano_modelo as ano_mode3_0_0_,

    www.algaworks.com 50

  • veiculo0_.fabricante as fabrican4_0_0_,veiculo0_.modelo as modelo5_0_0_,veiculo0_.valor as valor6_0_0_

    fromtab_veiculo veiculo0_

    whereveiculo0_.codigo=?

    Hibernate:update

    tab_veiculoset

    ano_fabricacao=?,ano_modelo=?,fabricante=?,modelo=?,valor=?

    wherecodigo=?

    www.algaworks.com 51

  • Captulo 4

    Mapeamento

    4.1. Identificadores

    A propriedade de identificao representa a chave primria de uma tabela dobanco de dados. Nos exemplos anteriores, a propriedade codigo de instncias deveculos representava o cdigo do veculo (chave primria) no banco de dados.

    Um exemplo tpico de mapeamento de identificadores o seguinte:

    @Id@GeneratedValuepublic Long getCodigo() {

    return codigo;}

    O identificador mapeado para a chave primria codigo. Podemos alterar o nomeda coluna usando @Column.

    @Id@GeneratedValue@Column(name = "cod_veiculo")public Long getCodigo() {

    return codigo;}

    A anotao @Id no mtodo getter marca a propriedade como um identificador,e a anotao @GeneratedValue diz que o valor do identificador ser gerado

    www.algaworks.com 52

  • automaticamente usando uma estratgia nativa do banco de dados, que no casodo MySQL, o auto-incremento.

    Este ltimo mapeamento poderia ser modificado para a seguinte forma (e osignificado seria o mesmo):

    @Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "cod_veiculo")public Long getCodigo() {

    return codigo;}

    A nica mudana realizada foi a incluso da propriedade strategy na anotao@GeneratedValue. Quando essa propriedade no informada, considerada aestratgia AUTO como padro.

    Existe um gerador de chave prprio do Hibernate chamado incrementincrement, que o famoso select max + 1. Para us-lo, inclumos a anotao @GenericGeneratore informamos a propriedade strategy igual a increment, damos um nome aesse gerador informando o atributo name e depois associamos esse gerador naanotao @GeneratedValue, informando na propriedade generator o mesmo nomeescolhido para o gerador.

    ...import javax.persistence.Id;import javax.persistence.Column;import javax.persistence.GeneratedValue;import org.hibernate.annotations.GenericGenerator;...

    @Id@GeneratedValue(generator = "inc")@GenericGenerator(name = "inc", strategy = "increment")@Column(name = "cod_veiculo")public Long getCodigo() {

    return codigo;}

    Apartir de agora, antes de fazer um insert de veculo, o framework executarum comando select para buscar o ltimo identificador usado, e ento far um

    www.algaworks.com 53

  • incremento para utilizar como prximo cdigo. Veja a query gerada quandopersistimos um novo veculo:

    Hibernate:select

    max(cod_veiculo)from

    tab_veiculo

    Esses so os identificadores mais usados. Consulte a documentao caso precisede outro tipo de gerador. Se mesmo assim no encontrar um que atenda suasnecessidades, voc poder desenvolver o seu prprio gerador customizado.

    4.2. Chaves compostas

    Para exemplificar o uso de chaves compostas, incluiremos os atributos cidadee placa como identificador de Veiculo. O atributo codigo no ser mais oidentificador, por isso precisaremos elimin-lo.

    Criaremos uma classe chamada VeiculoId para representar o identificador (achave composta) da entidade.

    import java.io.Serializable;import javax.persistence.Embeddable;

    @Embeddablepublic class VeiculoId implements Serializable {

    private static final long serialVersionUID = 1L;

    private String placa;private String cidade;

    public VeiculoId() {}

    public VeiculoId(String placa, String cidade) {super();this.placa = placa;this.cidade = cidade;

    www.algaworks.com 54

  • }public String getPlaca() {return placa;

    }

    public void setPlaca(String placa) {this.placa = placa;

    }

    public String getCidade() {return cidade;

    }

    public void setCidade(String cidade) {this.cidade = cidade;

    }

    // hashCode e equals

    }

    Veja que anotamos a classe VeiculoId com @Embeddable, pois ela ser sempreutilizada de forma embutida em outra classe.

    Na classe Veiculo, criamos um atributo id do tipo VeiculoId e anotamos seumtodo getter apenas com @EmbeddedId.

    ...import javax.persistence.EmbeddedId;

    @Entity@Table(name = "tab_veiculo")public class Veiculo {

    private VeiculoId id;

    private String fabricante;private String modelo;private Integer anoFabricacao;private Integer anoModelo;private BigDecimal valor;

    www.algaworks.com 55

  • @EmbeddedIdpublic VeiculoId getId() {

    return id;}

    // getters, setters, hashCode e equals

    }

    Para persistir um novo veculo, preciso informar a cidade e placa, que faz partedo identificador. Instanciaremos um VeiculoId e atribuiremos ao id do veculo.

    Veiculo veiculo = new Veiculo();veiculo.setId(new VeiculoId("ABC-1234", "Uberlndia"));veiculo.setFabricante("Honda");veiculo.setModelo("Civic");veiculo.setAnoFabricacao(2012);veiculo.setAnoModelo(2013);veiculo.setValor(new BigDecimal(71_300));

    manager.persist(veiculo);

    Para buscar um veculo pela chave, precisamos tambm instanciar um VeiculoIde chamar o mtodo find de EntityManager, passando como parmetro a instnciade VeiculoId.

    VeiculoId id = new VeiculoId("ABC-1234", "Uberlndia");Veiculo veiculo = manager.find(Veiculo.class, id);

    System.out.println("Placa: " + veiculo.getId().getPlaca());System.out.println("Cidade: " + veiculo.getId().getCidade());System.out.println("Fabricante: " + veiculo.getFabricante());System.out.println("Modelo: " + veiculo.getModelo());

    Dica:Dica: para recriar a tabela, configure no arquivo persistence.xml a propriedadehibernate.hbm2ddl.auto com valor igual a create.

    Nos prximos exemplos deste livro, voltaremos a usar chaves simples.

    www.algaworks.com 56

  • 4.3. Enumeraes

    Enumeraes em Java um tipo que define um nmero finito de valores(instncias), como se fossem constantes.

    Na classe Veiculo, incluiremos uma enumerao TipoCombustivel, pararepresentar os possveis tipos de combustveis que os veculos podem suportar.

    Primeiro, definimos a enum:

    public enum TipoCombustivel {

    ALCOOL,GASOLINA,DIESEL,BICOMBUSTIVEL

    }

    Depois, criamos a propriedade tipoCombustivel do tipo TipoCombustivel na classeVeiculo e configuramos seu mapeamento:

    public class Veiculo {

    ...

    private TipoCombustivel tipoCombustivel;

    ...

    @Column(name = "tipo_combustivel", nullable = false)@Enumerated(EnumType.STRING)public TipoCombustivel getTipoCombustivel() {

    return tipoCombustivel;}

    public void setTipoCombustivel(TipoCombustivel tipoCombustivel) {this.tipoCombustivel = tipoCombustivel;

    }

    ...

    www.algaworks.com 57

  • }O novo atributo foi mapeado como uma coluna normal, porm inclumos aanotao @Enumerated, para configurar o tipo da enumerao como string.Fizemos isso para que a coluna do banco de dados armazene o nome daconstante, e no o nmero que representa a opo na enumerao.

    Para inserir um novo veculo no banco de dados, atribumos tambm o tipo docombustvel, como voc pode ver no exemplo abaixo:

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("Ford");veiculo.setModelo("Focus");veiculo.setAnoFabricacao(2011);veiculo.setAnoModelo(2012);veiculo.setValor(new BigDecimal(41_500));veiculo.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);

    manager.persist(veiculo);

    Se o parmetro da anotao @Enumerated for alterado para EnumType.ORDINAL(padro), ser inserido o nmero que representa a opo na enumerao. No casoda gasolina, esse valor seria igual a 1.

    @Column(name = "tipo_combustivel", nullable = false)@Enumerated(EnumType.ORDINAL)public TipoCombustivel getTipoCombustivel() {

    return tipoCombustivel;}

    4.4. Propriedades temporais

    O tipo de uma propriedade automaticamente detectado, mas para umapropriedade do tipo Date ou Calendar, voc pode precisar definir a preciso dadata/hora, com a anotao @Temporal.

    @Temporal(TemporalType.DATE)@Column(name = "data_cadastro", nullable = false)public Date getDataCadastro() {

    www.algaworks.com 58

  • return dataCadastro;}

    O mapeamento acima, do atributo dataCadastro, diz que apenas a data importante, por isso, ao criarmos/atualizarmos a tabela usando o hbm2ddl, umacoluna do tipo DATE ser criada, se usarmos MySQL.

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("GM");veiculo.setModelo("Celta");veiculo.setAnoFabricacao(2008);veiculo.setAnoModelo(2008);veiculo.setValor(new BigDecimal(12_000));veiculo.setTipoCombustivel(TipoCombustivel.GASOLINA);veiculo.setDataCadastro(new Date());

    manager.persist(veiculo);

    A JPA no define a preciso que deve ser usada se @Temporal no for especificada,mas quando usamos Hibernate, as propriedades de datas usam a definioTemporalType.TIMESTAMP por padro. Outras opes so TemporalType.TIME eTemporalType.DATE.

    4.5. Propriedades transientes

    As propriedades de uma entidade so automaticamente mapeadas, se noespecificarmos nenhuma anotao. Por diversas vezes, podemos precisar criaratributos e/ou mtodos getters que no representam uma coluna no banco dedados. Nestes casos, devemos anotar com @Transient.

    @Transientpublic String getDescricao() {

    return this.getFabricante() + " " + this.getModelo()+ " " + this.getAnoFabricacao() + "/" + this.getAnoModelo()+ " por apenas " + this.getValor();

    }

    www.algaworks.com 59

  • A propriedade ser ignorada totalmente pelo mecanismo de persistncia. Omtodo getDescricao apenas um mtodo de negcio, que retorna uma descriocomercial do veculo.

    Veiculo veiculo = manager.find(Veiculo.class, 9L);System.out.println(veiculo.getDescricao());

    4.6. Objetos grandes

    Quando precisamos armazenar muitos dados em uma coluna, por exemplo umtexto longo, um arquivo qualquer ou uma imagem, mapeamos a propriedadecom a anotao @Lob.

    Objeto grande em caracteres (CLOB)

    Um CLOB (Character Large Object) um tipo de dado em bancos de dados quepode armazenar objetos grandes em caracteres (textos muito longos).

    Para mapear uma coluna CLOB em JPA, definimos uma propriedade com o tipoString, char[] ou Character[] e anotamos com @Lob.

    public class Veiculo {

    ...

    private String especificacoes;

    ...

    @Lobpublic String getEspecificacoes() {

    return especificacoes;}

    ...}

    Vamos persistir um novo veculo, incluindo uma especificao.

    www.algaworks.com 60

  • EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();

    tx.begin();

    StringBuilder especificacoes = new StringBuilder();especificacoes.append("Carro em excelente estado.\n");especificacoes.append("Completo, menos ar.\n");especificacoes.append("Primeiro dono, com manual de instruo ");especificacoes.append("e todas as revises feitas.\n");especificacoes.append("IPVA pago, aceita financiamento.");

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("VW");veiculo.setModelo("Gol");veiculo.setAnoFabricacao(2010);veiculo.setAnoModelo(2010);veiculo.setValor(new BigDecimal(17_200));veiculo.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo.setDataCadastro(new Date());veiculo.setEspecificacoes(especificacoes.toString());

    manager.persist(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    Poderamos incluir um texto muito maiormuito maior para a especificao do veculo.

    A coluna criada na tabela do tipo LONGTEXT, que um tipo de CLOB do MySQL.

    Podemos buscar um veculo normalmente e imprimir na sada as especificaes.

    EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo = manager.find(Veiculo.class, 15L);System.out.println("Veculo: " + veiculo.getModelo());System.out.println("-------");System.out.println(veiculo.getEspecificacoes());

    www.algaworks.com 61

  • manager.close();

    Veja a sada da execuo:

    Veculo: Gol-------Carro em excelente estado.Completo, menos ar.Primeiro dono, com manual de instruo e todas as revises feitas.IPVA pago, aceita financiamento

    Objeto grande binrio (BLOB)

    Um BLOB (Binary Large Object) um tipo de dado em bancos de dados que podearmazenar objetos grandes em binrio (arquivos diversos, incluindo executveis,msicas, imagens, etc).

    Para mapear uma coluna BLOB em JPA, definimos uma propriedade com o tipobyte[] ou Byte[] e anotamos com @Lob.

    public class Veiculo {

    ...

    private byte[] foto;

    ...

    @Lobpublic byte[] getFoto() {

    return foto;}

    ...}

    Vamos persistir um novo veculo, incluindo uma foto.

    // l bytes do arquivo da imagemPath path = FileSystems.getDefault().getPath("/caminho/da/imagem/ix35.jpg");byte[] foto = Files.readAllBytes(path);

    www.algaworks.com 62

  • EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("Hyundai");veiculo.setModelo("ix35");veiculo.setAnoFabricacao(2013);veiculo.setAnoModelo(2014);veiculo.setValor(new BigDecimal(100_000));veiculo.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo.setDataCadastro(new Date());veiculo.setFoto(foto);

    manager.persist(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    A coluna criada na tabela do tipo LONGBLOG, que um tipo de BLOB do MySQL.

    Podemos buscar um veculo normalmente, obter os bytes da imagem e exibirusando a classe javax.swing.JOptionPane.

    import java.awt.image.BufferedImage;import java.io.ByteArrayInputStream;import java.io.IOException;import javax.imageio.ImageIO;import javax.persistence.EntityManager;import javax.swing.ImageIcon;import javax.swing.JLabel;import javax.swing.JOptionPane;

    public class ExibindoImagem {

    public static void main(String[] args) throws IOException {EntityManager manager = JpaUtil.getEntityManager();Veiculo veiculo = manager.find(Veiculo.class, 16L);

    if (veiculo.getFoto() != null) {BufferedImage img = ImageIO.read(new ByteArrayInputStream(

    www.algaworks.com 63

  • veiculo.getFoto()));JOptionPane.showMessageDialog(null, new JLabel(

    new ImageIcon(img)));} else {

    System.out.println("Veiculo nao possui foto.");}

    manager.close();JpaUtil.close();

    }

    }

    4.7. Objetos embutidos

    Objetos embutidos so componentes de uma entidade, cujas propriedades somapeadas para a mesma tabela da entidade.

    Em algumas situaes, queremos usar a orientao a objetos para componentizarnossas entidades, mas manter os dados em uma nica tabela. Isso pode ser

    www.algaworks.com 64

  • interessante para evitar muitas associaes entre tabelas, e por consequncia,diversos joins durante as consultas.

    Outra situao comum o mapeamento de tabelas de sistemas legados, onde no permitido alterar a estrutura das tabelas.

    Queremos incluir novas colunas na tabela de veculos para armazenar algunsdados do proprietrio. Para no ficar tudo na entidade Veiculo, criaremos umaclasse Proprietario, que representa um proprietrio.

    @Embeddablepublic class Proprietario {

    private String nome;private String telefone;private String email;

    @Column(name = "nome_proprietario", nullable = false)public String getNome() {

    return nome;}

    public void setNome(String nome) {this.nome = nome;

    }

    @Column(name = "telefone_proprietario", nullable = false)public String getTelefone() {

    return telefone;}

    public void setTelefone(String telefone) {this.telefone = telefone;

    }

    @Column(name = "email_proprietario")public String getEmail() {

    return email;}

    public void setEmail(String email) {this.email = email;

    }

    www.algaworks.com 65

  • }Como as colunas sero criadas na tabela de veculos, mapeamos as propriedadesde Proprietario e definimos outros nomes de colunas.

    Note que a classe Proprietario foi anotada com @Embeddable.

    Na classe Veiculo, incluimos um novo atributo do tipo Proprietario com o getteranotado com @Embedded.

    public class Veiculo {

    ...

    private Proprietario proprietario;

    ...

    @Embeddedpublic Proprietario getProprietario() {

    return proprietario;}

    ...

    }

    Agora, para persistir um novo veculo, precisamos instanciar e relacionar comum Proprietario.

    EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Proprietario proprietario = new Proprietario();proprietario.setNome("Joo das Couves");proprietario.setTelefone("(34) 1234-5678");

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("VW");veiculo.setModelo("Gol");veiculo.setAnoFabricacao(2010);

    www.algaworks.com 66

  • veiculo.setAnoModelo(2010);veiculo.setValor(new BigDecimal(17_200));veiculo.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo.setDataCadastro(new Date());veiculo.setProprietario(proprietario);

    manager.persist(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    Veja as novas colunas que foram criadas na tabela.

    4.8. Associaes um-para-um

    O relacionamento um-para-um, tambm conhecido como one-to-one, pode serusado para dividir uma entidade em duas (criando duas tabelas), para ficar maisnormalizado e fcil de entender.

    Esse tipo de associao poderia ser usado entre Veiculo e Proprietario.

    Precisamos apenas anotar a classe Proprietario com @Entity e, opcionalmente,@Table. Alm disso, inclumos tambm um atributo codigo, para armazenar o

    www.algaworks.com 67

  • identificador da entidade (chave primria) e implementamos os mtodoshashCode e equals.

    @Entity@Table(name = "proprietario")public class Proprietario {

    private Long codigo;private String nome;private String telefone;private String email;

    @Id@GeneratedValuepublic Long getCodigo() {

    return codigo;}

    public void setCodigo(Long codigo) {this.codigo = codigo;

    }

    @Column(length = 60, nullable = false)public String getNome() {

    return nome;}

    public void setNome(String nome) {this.nome = nome;

    }

    @Column(length = 20, nullable = false)public String getTelefone() {

    return telefone;}

    public void setTelefone(String telefone) {this.telefone = telefone;

    }

    @Column(length = 255)public String getEmail() {

    return email;

    www.algaworks.com 68

  • }public void setEmail(String email) {this.email = email;

    }

    // hashCode e equals

    }

    Na classe Veiculo, adicionamos a propriedade proprietario e mapeamos com@OneToOne.

    public class Veiculo {

    ...

    private Proprietario proprietario;

    ...

    @OneToOnepublic Proprietario getProprietario() {

    return proprietario;}

    ...

    }

    Podemos tentar persistir um novo veculo associado a um proprietrio.

    EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Proprietario proprietario = new Proprietario();proprietario.setNome("Joo das Couves");proprietario.setTelefone("(34) 1234-5678");

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("VW");veiculo.setModelo("Gol");

    www.algaworks.com 69

  • veiculo.setAnoFabricacao(2010);veiculo.setAnoModelo(2010);veiculo.setValor(new BigDecimal(17_200));veiculo.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo.setDataCadastro(new Date());veiculo.setProprietario(proprietario);

    manager.persist(veiculo);

    tx.commit();manager.close();JpaUtil.close();

    Quando executamos o cdigo acima, recebemos uma exceo, dizendo que oobjeto do tipo Veiculo possui uma propriedade que faz referncia a um objetotransiente do tipo Proprietario.

    Caused by: org.hibernate.TransientPropertyValueException: objectreferences an unsaved transient instance - save the transientinstance before flushing: Veiculo.proprietario -> Proprietario

    Precisamos de uma instncia persistida de proprietrio para atribuir ao veculo.

    Proprietario proprietario = new Proprietario();proprietario.setNome("Joo das Couves");proprietario.setTelefone("(34) 1234-5678");

    manager.persist(proprietario);

    Veiculo veiculo = new Veiculo();veiculo.setFabricante("VW");veiculo.setModelo("Gol");veiculo.setAnoFabricacao(2010);veiculo.setAnoModelo(2010);veiculo.setValor(new BigDecimal(17_200));veiculo.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo.setDataCadastro(new Date());veiculo.setProprietario(proprietario);

    manager.persist(veiculo);

    Veja a sada da execuo:

    www.algaworks.com 70

  • Hibernate:insertinto

    proprietario(email, nome, telefone)

    values(?, ?, ?)

    Hibernate:insertinto

    tab_veiculo(ano_fabricacao, ano_modelo, data_cadastro, fabricante, modelo,proprietario_codigo, tipo_combustivel, valor)

    values(?, ?, ?, ?, ?, ?, ?, ?)

    Note que foi criada uma coluna proprietario_codigo na tabela tab_veiculo.

    Por padro, o nome da coluna definido com o nome do atributo da associao,mais underscore, mais o nome do atributo do identificador da entidade destino.Podemos mudar isso com a anotao @JoinColumn.

    @OneToOne@JoinColumn(name = "cod_proprietario")public Proprietario getProprietario() {

    return proprietario;}

    O relacionamento one-to-one aceita referncias nulas, por padro. Podemosobrigar a atribuio de proprietrio durante a persistncia de Veiculo, incluindoo atributo optional com valor false, na anotao @OneToOne.

    @OneToOne(optional = false)public Proprietario getProprietario() {

    return proprietario;}

    Dessa forma, se tentarmos persistir um veculo sem proprietrio, uma exceo lanada.

    Caused by: org.hibernate.PropertyValueException: not-null propertyreferences a null or transient value: Veiculo.proprietario

    www.algaworks.com 71

  • Consultando veculos

    Quando consultamos veculos, o provedor JPA executa uma consulta doproprietrio para cada veculo encontrado:

    EntityManager manager = JpaUtil.getEntityManager();

    List veiculos = manager.createQuery("from Veiculo", Veiculo.class).getResultList();

    for (Veiculo veiculo : veiculos) {System.out.println(veiculo.getModelo() + " - "

    + veiculo.getProprietario().getNome());}

    manager.close();JpaUtil.close();

    Veja as queries executadas:

    Hibernate:select

    veiculo0_.codigo as codigo1_1_,veiculo0_.ano_fabricacao as ano_fabr2_1_,veiculo0_.ano_modelo as ano_mode3_1_,veiculo0_.data_cadastro as data_cad4_1_,veiculo0_.fabricante as fabrican5_1_,veiculo0_.modelo as modelo6_1_,veiculo0_.proprietario_codigo as propriet9_1_,veiculo0_.tipo_combustivel as tipo_com7_1_,veiculo0_.valor as valor8_1_

    fromtab_veiculo veiculo0_

    Hibernate:select

    proprietar0_.codigo as codigo1_0_0_,proprietar0_.email as email2_0_0_,proprietar0_.nome as nome3_0_0_,proprietar0_.telefone as telefone4_0_0_

    fromproprietario proprietar0_

    www.algaworks.com 72

  • whereproprietar0_.codigo=?

    Podemos mudar esse comportamento padro e executar apenas uma queryusando recursos da JPQL, mas ainda no falaremos sobre isso.

    Se consultarmos um veculo pelo identificador, a query inclui um left join ouinner join com a tabela de proprietrios, dependendo do atributo optional domapeamento @OneToOne.

    EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo = manager.find(Veiculo.class, 1L);

    System.out.println(veiculo.getModelo() + " - "+ veiculo.getProprietario().getNome());

    manager.close();JpaUtil.close();

    Veja a query executada com @OneToOne(optional = false).

    selectveiculo0_.codigo as codigo1_1_1_,veiculo0_.ano_fabricacao as ano_fabr2_1_1_,veiculo0_.ano_modelo as ano_mode3_1_1_,veiculo0_.data_cadastro as data_cad4_1_1_,veiculo0_.fabricante as fabrican5_1_1_,veiculo0_.modelo as modelo6_1_1_,veiculo0_.proprietario_codigo as propriet9_1_1_,veiculo0_.tipo_combustivel as tipo_com7_1_1_,veiculo0_.valor as valor8_1_1_,proprietar1_.codigo as codigo1_0_0_,proprietar1_.email as email2_0_0_,proprietar1_.nome as nome3_0_0_,proprietar1_.telefone as telefone4_0_0_

    fromtab_veiculo veiculo0_

    inner joinproprietario proprietar1_

    on veiculo0_.proprietario_codigo=proprietar1_.codigo

    www.algaworks.com 73

  • whereveiculo0_.codigo=?

    Associao bidirecional

    A associao que fizemos entre veculo e proprietrio unidirecional, ou seja,podemos obter o proprietrio a partir de um veculo, mas no conseguimos obtero veculo a partir de um proprietrio.

    Para tornar a associao um-para-um bidirecional e ento conseguirmos obtero veculo a partir de um proprietrio, precisamos apenas incluir uma novapropriedade na classe Proprietario e mapearmos com @OneToOne usando oatributo mappedBy.

    @Entity@Table(name = "proprietario")public class Proprietario {

    ...

    private Veiculo veiculo;

    ...

    @OneToOne(mappedBy = "proprietario")public Veiculo getVeiculo() {

    return veiculo;}

    ...

    }

    O valor de mappedBy deve ser igual ao nome da propriedade na classe Veiculo queassocia com Proprietario.

    Agora, podemos consultar um proprietrio e obter o veculo dele.

    Proprietario proprietario = manager.find(Proprietario.class, 1L);

    www.algaworks.com 74

  • System.out.println(proprietario.getVeiculo().getModelo() + " - "+ proprietario.getNome());

    4.9. Associaes muitos-para-um

    Na ltima seo, mapeamos a propriedade proprietario na entidade Veiculocom um-para-um. Mudaremos o relacionamento agora para many-to-one. Dessaforma, um veculo poder possuir apenas um proprietrio, mas um proprietriopoder estar associado a muitos veculos.

    Vamos remover a propriedade veiculo da entidade Proprietario e alterar omapeamento de proprietario na classe Veiculo.

    public class Veiculo {

    ...

    private Proprietario proprietario;

    ...

    @ManyToOne@JoinColumn(name = "cod_proprietario")public Proprietario getProprietario() {

    return proprietario;}

    ...

    }

    A anotao @ManyToOne indica a multiplicidade do relacionamento entre veculo eproprietrio.

    Vamos persistir um proprietrio e 2 veculos, que pertencem ao mesmo dono.

    www.algaworks.com 75

  • EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    Proprietario proprietario = new Proprietario();proprietario.setNome("Joo das Couves");proprietario.setTelefone("(34) 1234-5678");

    manager.persist(proprietario);

    Veiculo veiculo1 = new Veiculo();veiculo1.setFabricante("GM");veiculo1.setModelo("Celta");veiculo1.setAnoFabricacao(2006);veiculo1.setAnoModelo(2006);veiculo1.setValor(new BigDecimal(11_000));veiculo1.setTipoCombustivel(TipoCombustivel.GASOLINA);veiculo1.setDataCadastro(new Date());veiculo1.setProprietario(proprietario);

    manager.persist(veiculo1);

    Veiculo veiculo2 = new Veiculo();veiculo2.setFabricante("VW");veiculo2.setModelo("Gol");veiculo2.setAnoFabricacao(2010);veiculo2.setAnoModelo(2010);veiculo2.setValor(new BigDecimal(17_200));veiculo2.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo2.setDataCadastro(new Date());veiculo2.setProprietario(proprietario);

    manager.persist(veiculo2);

    tx.commit();manager.close();JpaUtil.close();

    Para deixar a associao bidirecional, precisamos mapear um atributo naentidade Proprietario, usando a @OneToMany. Veremos isso na prxima seo.

    www.algaworks.com 76

  • 4.10. Colees um-para-muitos

    A anotao @OneToMany deve ser utilizada para mapear colees.

    Mapearemos o inverso da associao many-to-one, que fizemos na ltima seo,indicando que um proprietrio pode ter muitos veculos.

    Incluiremos a propriedade veiculos na entidade Proprietario, do tipo List.

    public class Proprietario {

    ...

    private List veiculos;

    ...

    @OneToMany(mappedBy = "proprietario")public List getVeiculos() {

    return veiculos;}

    ...

    }

    Para testar esse relacionamento, execute o cdigo abaixo, que busca umproprietrio e lista todos os veculos dele.

    EntityManager manager = JpaUtil.getEntityManager();

    Proprietario proprietario = manager.find(Proprietario.class, 1L);

    System.out.println("Proprietrio: " + proprietario.getNome());

    for (Veiculo veiculo : proprietario.getVeiculos()) {System.out.println("Veculo: " + veiculo.getModelo());

    www.algaworks.com 77

  • }manager.close();JpaUtil.close();

    Veja a sada da execuo do cdigo acima:

    Hibernate:select

    proprietar0_.codigo as codigo1_0_0_,proprietar0_.email as email2_0_0_,proprietar0_.nome as nome3_0_0_,proprietar0_.telefone as telefone4_0_0_

    fromproprietario proprietar0_

    whereproprietar0_.codigo=?

    Proprietrio: Joo das CouvesHibernate:

    selectveiculos0_.cod_proprietario as cod_prop9_0_1_,veiculos0_.codigo as codigo1_1_1_,veiculos0_.codigo as codigo1_1_0_,veiculos0_.ano_fabricacao as ano_fabr2_1_0_,veiculos0_.ano_modelo as ano_mode3_1_0_,veiculos0_.data_cadastro as data_cad4_1_0_,veiculos0_.fabricante as fabrican5_1_0_,veiculos0_.modelo as modelo6_1_0_,veiculos0_.cod_proprietario as cod_prop9_1_0_,veiculos0_.tipo_combustivel as tipo_com7_1_0_,veiculos0_.valor as valor8_1_0_

    fromtab_veiculo veiculos0_

    whereveiculos0_.cod_proprietario=?

    Veculo: CeltaVeculo: Gol2

    A primeira query foi executada para buscar o proprietrio. A segunda, parapesquisar a lista de veculos do proprietrio.

    www.algaworks.com 78

  • Note que a segunda consulta s foi executada quando chamamos o mtodogetVeiculos. Esse comportamento chamado de lazy-loading, e ser estudadomais adiante.

    4.11. Colees muitos-para-muitos

    Para praticar o relacionamento many-to-many, criaremos uma entidade Acessorio,que representa os acessrios que um carro pode ter. Dessa forma, um veculopoder possuir vrios acessrios e um acessrio poder estar associado a vriosveculos.

    A classe Acessorio uma entidade sem nenhuma novidade nos mapeamentos.

    @Entity@Table(name = "acessorio")public class Acessorio {

    private Long codigo;private String descricao;

    @Id@GeneratedValuepublic Long getCodigo() {

    return codigo;}

    public void setCodigo(Long codigo) {this.codigo = codigo;

    }

    @Column(length = 60, nullable = false)public String getDescricao() {

    return descricao;}

    www.algaworks.com 79

  • public void setDescricao(String descricao) {this.descricao = descricao;

    }

    // hashCode e equals

    }

    Na entidade Veiculo, criamos um atributo acessorios do tipo Set. Definimoscomo um conjunto, pois um veculo no poder possuir o mesmo acessriorepetido. Usamos a anotao @ManyToMany para mapear a propriedade de coleo.

    public class Veiculo {

    ...

    private Set acessorios = new HashSet();

    ...

    @ManyToManypublic Set getAcessorios() {

    return acessorios;}

    ...

    }

    Esse tipo de relacionamento precisar de uma tabela de associao para que amultiplicidade muitos-para-muitos funcione. O recurso hbm2ddl poder criar astabelas automaticamente.

    www.algaworks.com 80

  • Por padro, um mapeamento com @ManyToMany cria a tabela de associao com osnomes das entidades relacionadas, separados por underscore, com duas colunas,com nomes tambm gerados automaticamente.

    Podemos customizar o nome da tabela de associao e das colunas com aanotao @JoinTable.

    @ManyToMany@JoinTable(name = "veiculo_acessorios",

    joinColumns = @JoinColumn(name = "cod_veiculo"),inverseJoinColumns = @JoinColumn(name = "cod_acessorio"))

    public Set getAcessorios() {return acessorios;

    }

    Neste exemplo, definimos o nome da tabela de associao comoveiculo_acessorios, o nome da coluna que faz referncia para a tabela de veculoscomo cod_veiculo e da coluna que referencia tabela de acessrios comocod_acessorio (lado inverso).

    Vamos inserir e relacionar alguns acessrios e veculos.

    www.algaworks.com 81

  • EntityManager manager = JpaUtil.getEntityManager();EntityTransaction tx = manager.getTransaction();tx.begin();

    // instancia acessriosAcessorio alarme = new Acessorio();alarme.setDescricao("Alarme");

    Acessorio arCondicionado = new Acessorio();arCondicionado.setDescricao("Ar condicionado");

    Acessorio bancosDeCouro = new Acessorio();bancosDeCouro.setDescricao("Bancos de couro");

    Acessorio direcaoHidraulica = new Acessorio();direcaoHidraulica.setDescricao("Direo hidrulica");

    // persiste acessriosmanager.persist(alarme);manager.persist(arCondicionado);manager.persist(bancosDeCouro);manager.persist(direcaoHidraulica);

    // instancia veculosVeiculo veiculo1 = new Veiculo();veiculo1.setFabricante("VW");veiculo1.setModelo("Gol");veiculo1.setAnoFabricacao(2010);veiculo1.setAnoModelo(2010);veiculo1.setValor(new BigDecimal(17_200));veiculo1.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo1.setDataCadastro(new Date());veiculo1.getAcessorios().add(alarme);veiculo1.getAcessorios().add(arCondicionado);

    Veiculo veiculo2 = new Veiculo();veiculo2.setFabricante("Hyundai");veiculo2.setModelo("i30");veiculo2.setAnoFabricacao(2012);veiculo2.setAnoModelo(2012);veiculo2.setValor(new BigDecimal(53_500));veiculo2.setTipoCombustivel(TipoCombustivel.BICOMBUSTIVEL);veiculo2.setDataCadastro(new Date());veiculo2.getAcessorios().add(alarme);

    www.algaworks.com 82

  • veiculo2.getAcessorios().add(arCondicionado);veiculo2.getAcessorios().add(bancosDeCouro);veiculo2.getAcessorios().add(direcaoHidraulica);veiculo2.getAcessorios().add(direcaoHidraulica);

    // persiste veculosmanager.persist(veiculo1);manager.persist(veiculo2);

    tx.commit();manager.close();JpaUtil.close();

    O provedor de persistncia incluir os registros nas 3 tabelas.

    Consultando acessrios de um veculo

    Podemos iterar nos acessrios de um veculo usando o mtodo getAcessorios daclasse Veiculo.

    EntityManager manager = JpaUtil.getEntityManager();

    Veiculo veiculo = manager.find(Veiculo.class, 2L);System.out.println("Veculo: " + veiculo.getModelo());

    for (Acessorio acessorio : veiculo.getAcessorios()) {System.out.println("Acessrio: " + acessorio.getDescricao());

    }

    manager.close();JpaUtil.close();

    Veja a sada da execuo do cdigo acima:

    Hibernate:select

    veiculo0_.codigo as codigo1_1_0_,veiculo0_.ano_fabricacao as ano_fabr2_1_0_,veiculo0_.ano_modelo as ano_mode3_1_0_,veiculo0_.data_cadastro as data_cad4_1_0_,veiculo0_.fabricante as f