Você está na página 1de 44

Tópicos em Engenharia de Software II – 2011/2

Prof. Vitor Alcântara Batista


 Introdução
 Arquitetura
 Mapeamento de Entidades
 Mapeamento de Associações
 Persistindo objetos
 Consultando objetos
 Java Persistence API
◦ É um padrão definido pelo JCP para trabalhar com
persistência de dados.
◦ O líder a especificação foi Gavin King, o criador do
Hibernate.
◦ Existem várias implementações disponíveis no
mercado.
 Hibernate, SAP Netweaver AS, TopLink, EclipseLink,
Open,JPA, Kodo, JPOX, Amber, entre outras...
 Hibernate é um framework de mapeamento
Objeto/Relacional para Java e
.NET(NHibernate)
 Oferece serviços para consulta e recuperação
de dados
 Objetivo: liberar o desenvolvedor de grande
parte da programação relacionada a
persistência de dados
 Suporte aos principais SGDBs
 Projeto Hibernate
◦ Mantido atualmente pelo JBoss Inc.
◦ Projeto Open-source
 Adotado por muitos projetos no mundo inteiro
◦ Versão 3 foi base para a especificação de
persistência da JPA
 Hibernate implementa a JPA.
 Mapeamento pode ser feito em arquivos xml
separados do código fonte

 Pode ser feito com tags xDoclet no código


fonte

 Pode ser feito com Annotations do Java 1.5 e


Hibernate 3
 Entidades:
◦ “Tipicamente” representam uma tabela no banco de
dados.
◦ Cada instância de uma entidade corresponde a uma
linha na tabela.

◦ Seguindo os padrões da JPA cada entidade DEVE atender


os requisitos:
 Ser anotada coma anotação @Entity.
 Deve ter um construtor sem argumentos, público ou
protegido.
 Não pode ser declarada final. Nenhum método ou variável de
instância pode ser declarada como final.
 Variáveis de instância persistentes não devem ser declaradas
públicas e só podem ser acessadas pelos métodos da classe.
 Uma Entidade é mapeada com a anotação
◦ @Entity
 Pode ser definido um nome para a tabela do banco de dados
através do atributo name da anotação.
 Um objeto que não é uma entidade, mas que tem
atributos persistentes ou informações de
mapeamento, deve ser mapeado com a anotação
@MappedSuperclass
 Objetos mapeados com a anotação
@MappedSuperclass não podem ser pesquisados
no banco, ou seja, não existe uma tabela para
aquele objeto.
 A anotação @MappedSuperclass é utilizada para
hierarquias de objetos.
 Entidades que extendem não-Entidades ao
serem salvas, ignoram os dados da
superclasse, a não ser que a superclasse
utilize a anotação @MappedSuperclass
 Ou seja, os dados da superclasse são

transientes e nunca serão persistentes.


 Como anotar a entidade

import javax.persistence.Entity;

@Entity
public class Aluno
{

}
 Existem 3 estratégias de mapeamento de
polimorfismo
Flexibilidad

 Uma tabela para toda a hierarquia de classes


e

 Uma tabela por classe concreta


Desempenho

 Uma tabela por subclasse


 Uma tabela para toda a hierarquia de classes
◦ Toda a hierarquia de classes é representada por uma única
tabela no banco de dados
◦ Propriedades de uma subclasse específica não podem ser
anotadas com a anotação @NotNull
◦ Utiliza a anotação @DiscriminatorColumn para identificar a
instância
 Uma tabela para toda a hierarquia de classe
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name=“TYPE",
discriminatorType=DiscriminatorType.STRING)
public class Person { …}

@Entity
@DiscriminatorValue(“EMP")
public class Employee { … }

@Entity
@DiscriminatorValue(“STU")
public class Student { … }
 Uma tabela para toda a hierarquia de classe:
◦ @Inheritance e @DiscriminatorColumn só devem ser
utilizados no topo da hierarquia.
◦ Caso não seja informado um name para o
DiscriminatorType o default é DTYPE
◦ Caso não seja informado um valor para o
DiscriminatorValue o default é o nome da entidade,
conforme definido na anotação @Entity.
 Uma tabela por classe concreta
◦ Cada classe concreta será armazenada em uma
tabela distinta
 Uma tabela por classe concreta
◦ A classe abstrata Person não é mapeada
◦ As sub-classes são mapeadas como uma classe qualquer

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Person { … }

@Entity
public class Employee extends Person { … }

@Entity
public class Student extends Person { … }
 Uma tabela por classe concreta
◦ Cada classe será armazenada em uma tabela
◦ Estratégia mais “orientada à objeto”
◦ Necessita de mais joins entre tabelas para
recuperar dados.
◦ Não suporta muito bem associações polimórficas.
 Uma tabela por classe
 Uma tabela por classe
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Person { …}

@Entity
public class Employee { … }

@Entity
@PrimaryKeyJoinColumn(name=“Person_ID")
public class Student { … }
 Uma tabela por classe
◦ Cada classe será armazenada em uma tabela,
inclusive a classe pai, sendo ela abstrata ou não.
◦ Necessita de um único join para recuperar os
dados.
◦ Pode impactar no desempenho de uma aplicação
devido ao número de joins que podem ser feitos
em uma hierarquia completa.
 A primeira estratégia é a mais simples mas
restringe a utilização de not-null
◦ Utilizado quando a principal diferença entre as
diferentes sub-classes é seu comportamento,
possuindo quase o mesmo conjunto de propriedades
 A segunda resolve o problema do not-null e da
diferença entre o conjunto de propriedades
◦ Mas apresenta problema com associação polimórfica
 A terceira é a mais flexível
◦ Permite associações com classes abstratas
◦ Mas necessita de mais joins para recuperar dados
 A anotação @Id define o identificador único
da classe
 Toda classe deve declarar um identificador

obrigatoriamente
 A anotação @GeneratedValue é utilizada

para definir a forma com que o id será


gerado.
@Id
@GeneratedValue (strategy=GenerationType.AUTO)
public Long getId(){}
 toda entidade é herdeira de
ObjetoPersistente, que contém o Identificador
@MappedSuperclass public abstract class ObjetoPersistente
implements Comparable<Object>
{
private Long id;

@Id @GeneratedValue public final Long getId()

@Entity public final class Usuário extends EntidadePersistente


 Tipos de associações:
◦ 1–1
◦ 1 – N (composição)
◦ 1–N
◦ N-N
Pessoa 1 1 Endereço
+pessoa +endereco

@OneToOne @OneToOne(mappedBy=“endereco”)
@JoinColumn public Pessoa getPessoa(){…}
public Endereço getEndereco(){…}

 A entidade que possui a chave estrangeira é


responsável pela associação (a associação é
persistida quando o objeto é persistido).
Pessoa 1 1 Endereço
+pessoa +endereco

@OneToOne (cascade=CascadeType.ALL) @OneToOne(mappedBy=“endereco”)


@JoinTable(name=“PessoaEndereco", public Pessoa getPessoa(){…}
joinColumns = @JoinColumn(name =
“pessoa_fk"),
inverseJoinColumns = @JoinColumn(name
= “endereco_fk") )
public Endereço getEndereco(){…}

 Uma tabela é criada com o nome de


PessoaEndereco e em cada linha armazenará o
id da Pessoa e o id do Endereço nas colunas
pessoa_fk e endereco_fk,respectivamente.
@OneToMany(mappedBy=“responsavel“) @ManyToOne(cascade=CascadeType.ALL)
public Collection getDependetes(){…} @JoinColumn
@org.hibernate.annotations.Cascade(value =
org.hibernate.annotations.CascadeType.
DELETE_ORPHAN)
public Pessoa getResponsavel(){…}

 Cuidado com o nome das chaves, eles são os responsáveis por


tornar a associação bidirecional
 As opções de cascade devem ser feitas de acordo com o tipo de
associação
◦ Se existir uma composição entre Pessoa e Dependente, a opção de
cascade do lado de Pessoa deveria ser “all-delete-orphan ”
 Isso vincularia o ciclo de vida de Dependente a Pessoa.
Pessoa 1 0..* Dependente
+responsavel +dependentes
@OneToMany @Entity
@JoinTable(name=“Pessoa_Dependente", public class Dependente
joinColumns = @JoinColumn(name = {

“pessoa_id"), inverseJoinColumns =
//Não existe o atributo
@JoinColumn(name =“dependente_id") ) pessoa
public Collection getDependetes(){…} ...
}

 Também é possível fazer o mapeamento ManyToOne e


OneToMany utilizando uma tabela secundária.
 O comportamento é o mesmo do mapeamento
OneToOne com tabela secundária.
 Este caso é recomendado quando o relacionamento é
unidirecional em casos OneToMany.
Pessoa 1 0..* Dependente
+responsavel +dependentes
@OneToMany(mappedBy=“responsavel") @ManyToOne
public Collection getDependetes(){…} @JoinColumn(name=“PESSOA_DEP")
public Pessoa getResponsavel(){…}

 Em associações 1 – N SEMPRE o lado N


comandará a associação
◦ A associação é persistida quando Dependente for
persistido.
 Esta regra é uma boa prática, pois é
otimizada e em geral executará apenas uma
ação via cascade ao invés de N.
Pessoa 0..* 0..*
Função
+pessoas +funcoes

@ManyToMany(mappedBy=“pessoas") @ManyToMany(cascade =
public Collection getFuncoes(){…} { CascadeType.PERSIST,
CascadeType.MERGE })
@JoinTable
public Pessoa getPessoas(){…}

 Em mapeamento many-to-many é importante


utilizar o mappedBy para indicar qual lado
manda na relação.
 Cascade para deleção deve ser utilizado com
cuidado, já que uma entidade com diversas
associações pode ser apagada quando somente
um das entidades associados for apagada.
 Importância do cascade
◦ O cascade define a propagação das operações de
persistência
◦ Importante para o ciclo de vida das entidades
relacionadas
◦ Cascade mal planejado pode destruir uma aplicação
 Problemas de desempenho
 Perda de dados por cascade - CascadeType.Remove
 Deixar “lixo” no banco de dados
 Eager: Utiliza um outer join para recuperar os
objetos associados quando o objeto base é
carregado.
 Lazy: Carrega os objetos associados somente
quando eles forem utilizados pelo objeto base.
@ManyToMany (fetch=FetchType.EAGER)

 Relacionamentos OneToMany e ManyToMany têm


por default o tipo de recuperação Lazy, enquanto
os relacionamentos OneToOne e ManyToOne tem
o tipo de recuperação Eager.
 Principais Interfaces do JPA
◦ EntityManagerFactory
◦ EntityManager
◦ EntityTransaction
 Fornece instâncias de EntityManager
 Todas as instâncias fornecidas, conectam

num mesmo banco e são geradas, por


padrão, com as mesmas configurações.
 A fábrica, usualmente, está associada à

aplicação e tem o mesmo ciclo de vida dela


private static EntityManagerFactory emf;
emf = Persistence.createEntityManagerFactory("praxis");

Arquivo persistence.xml
<persistence-unit name="praxis">

<properties>
<property name="hibernate.archive.autodetection“ value="class, hbm" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.connection.driver_class"
value="org.hsqldb.jdbcDriver" />
<property name="hibernate.connection.url"
value="jdbc:hsqldb:hsql://localhost:9001/" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="create-dropk" />
</properties>
</persistence-unit>
 Semelhante à classe Session do Hibernate.
 Utilizada para persistir, excluir, recuperar

pelo ID e fazer consulta por objetos.


 Principais métodos

◦ persists(Object)
◦ remove(Object)
◦ find(Class<T>, Object)
◦ getReference(Class<T>, Object)
◦ createQuery(String)
◦ getTransaction()
 Persistindo um objeto
EntityManager em = emf.createEntityManager();
Aluno a = new Aluno();
a.setNome("Vitor");
em.persist(a);

 Recuperando um objeto pelo ID


EntityManager em = emf.createEntityManager();
Aluno a = em.find(Aluno.class, new Long(1));
 Recuperando todos os objetos de uma classe
List<Aluno> alunos = em.createQuery("from Aluno").getResultList();

 Recuperando objetos de um tipo com filtro


List<Pessoa> alunos = em.createQuery(
"select nome from Aluno as aluno where aluno.nome = ?1")
.setParameter(1, "Vitor")
.getResultList();

Query q = em.createQuery("select nome from Aluno as aluno where


aluno.nome = :nome");
q.setParameter(“nome”, “Vitor”);
List<Pessoa> alunos = q.getResultList();
 Só é necessário fazer joins quando deseja-se
filtrar o resultado por um atributo de outra
entidade.
 Ao recuperar um objeto, é possível navegar

pelas associações e o hibernate recupera as


instâncias associadas.
 HQL
List<Pessoa> alunos = em.createQuery(
"select aluno.nome from Aluno as aluno JOIN aluno.endereco as endereco
where endereco.cidade = ?1“).setParameter(1, "BH“)
.getResultList();

 Consulta executada pelo Hibernate


select
aluno.nome
from
Aluno
inner join
Pessoa on Pessoa.id=Aluno.id
inner join
Endereco on Pessoa.id=Endereco.pessoa_id
where
Endereco.cidade=?
 Criar um novo projeto, configurar o Hibernate
e mapear um modelo de Entidades.
 Criar código Java (uma nova classe
executável) para reproduzir um conjunto de
objetos.
 Executar consultas nesses objetos e mostrá-

los no console

Você também pode gostar