O Load ou Fetch é a indicação de como a associação deve ser recuperada, definindo se, ao carregar um objeto que possui outros objetos associados, os dados das associações também devem ser recuperados.
q
Temos dois tipos:
1 FetchType.EAGER: ao carregar um objeto, carrega todas as associações imediatamente; 1 FetchType.LAZY: ao carregar um objeto, não carrega as associações imediatamente,
somente nas chamadas dos getters.
Em toda associação @OneToOne, @OneToMany e @ManyToMany, podemos definir o tipo de Fetch, sendo que o default é FecthType.LAZY. Para trocar o tipo de Fetch em uma associação, usa-se o atributo fetch das anotações.
q
1 Em toda associação: @OneToOne, @OneToMany e @ManyToMany; 1 Default é FecthType.LAZY;
1 Para trocar o tipo de Fetch em uma associação, usa-se:
@OneToOne(fetch=FetchType.EAGER) @JoinColumn(name=”user_id”) private Profile getUser() { return user;
}
A escolha de qual estratégia usar depende do sistema sendo desenvolvido e de requisitos de desempenho e tempo de codificação. Eager demanda pouca codificação porque o próprio hibernate já busca todos os dados dos objetos associados. O problema é o desempenho, pois podemos ter várias associações e podem ser buscados dados que não serão usados no processo. Já Lazy demanda um pouco mais de codificação, mesmo em HQL (que será visto em outra sessão) ou na manutenção da sessão, mas é mais eficiente, pois as buscas são feitas sob demanda, explicitamente. Preferencialmente os sistemas usam Lazy Fetch.
q
O que usar? 1 Eager:
2 Pouca codificação;
2 Problemas de desempenho, pois busca todas as associações. 1 Lazy – Default e Preferencial:
2 Mais codificação;
te – A ss oc ia çõ es
Associação Um-para-Um
Uma associação Um-para-Um indica que um objeto possui relação com somente outro, por exemplo, uma pessoa que possui um e somente um endereço. Nessa relação, um endereço é também de somente uma pessoa. A figura a seguir ilustra como seria a associação, através de uma ligação entre as duas entidades, usando notação UML.
Pessoa - nome : String Disciplina - rua : String - numero : int 1 1
Nesta notação, as caixas representam as classes (e portanto são modelos para os objetos) e a conexão entre elas representa a associação. O número perto da classe Endereço indica que uma Pessoa pode ter um (1) Endereço. O número perto de Pessoa indica que um Endereço pode ser de uma (1) Pessoa.
Uma associação pode ser bidirecional e, nesse caso, um dos lados deve ser o proprietário da associação. No proprietário, a propriedade da associação é anotada com @OneToOne e é responsável por manter a coluna de associação. É nessa classe que se declara a coluna de ligação, que torna a associação existente no banco de dados. No lado oposto é usada a anotação @OneToOne, com um atributo chamado mappedBy, para indicar a propriedade do lado inverso, que representa a associação.
q
Um dos lados deve ser o dono ou proprietário da associação. 1 O proprietário:
2 Na propriedade da associação anota-se com @OneToOne; 2 É responsável por manter a associação;
2 Declara a coluna de ligação.
1 Do lado oposto ao proprietário, usamos: 2 Anotação @OneToOne;
2 Com atributo mappedBy.
1 @JoinColumn é usado para indicar qual é o campo que liga das duas tabelas
As anotações utilizadas são @OneToOne, que deve ser colocada na classe proprietária da associação, bem como na outra classe. A tabela 8.1 mostra os atributos dessa anotação.
Atributos Descrição
cascade Opcional. O tipo de cascateamento entre as operações.
fetch Opcional. Se a associação será carregada ou não (lazy) ao se buscar um objeto desse tipo. mappedBy Opcional. O campo que é dono do relacionamento. Esse atributo só é configurado do lado
inverso da associação (o que não é o dono). UML
Unified Modeling Language, uma notação usada para descrever sistemas em várias visões. Mais detalhes em: http://www.uml.org/ Figura 8.1 Associação Um-para-Um. Tabela 8.1 Atributos de @OneToOne.
JA VA – F ra m ew or ks e A pl ic aç õe s Co rp or at iv as
Já a anotação @JoinColumn é usada para indicar o campo que faz a ligação entre as duas tabelas da relação, e seus atributos são apresentados na tabela a seguir. A tabela 8.2 mostra alguns atributos de @JoinColumn.
Atributos Descrição
name Opcional. Nome da coluna de ligação entre as tabelas. nullable Opcional. Se a coluna pode ser NULL.
table Opcional. Nome da tabela onde está a coluna de ligação. unique Opcional. Se a propriedade é uma chave única.
As classes da figura 8.1 podem ser mapeadas para as seguintes tabelas:
create table tb_pessoa (
id integer NOT NULL PRIMARY KEY, pess_nome character varying(30) NOT NULL); create table tb_endereco (
id integer NOT NULL PRIMARY KEY, end_rua character varying(30) NOT NULL, end_numero integer NOT NULL);
alter table tb_pessoa add end_id integer not null REFERENCES tb_endereco(id); CREATE SEQUENCE seq_pess_id
INCREMENT 1 MINVALUE 1
MAXVALUE 9223372036854775807 START 11
CACHE 1;
CREATE SEQUENCE seq_end_id INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807 START 11
CACHE 1;
A classe Pessoa deve ser anotada conforme o trecho de código a seguir:
package com.cursojava.model; // imports
@Entity
@Table (name=”tb_pessoa”)
@SequenceGenerator(name=”sequencia”, sequenceName=”seq_pess_id”) public class Pessoa implements Serializable {
private Long id; private String nome; private Endereco endereco; @Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”sequencia”)
public Long getId() { return id;
Tabela 8.2
Atributos de @JoinColumn.
te – A ss oc ia çõ es }
public void setId(Long id) { this.id = id; }
@Column(updatable=true, name=”pess_nome”, nullable=false, length=30) public String getNome() {
return this.nome; }
public void setNome(String nome) { this.nome = nome;
}
@OneToOne(cascade=CascadeType.ALL) @JoinColumn(name=”end_id”, updatable=true) public Endereco getEndereco() {
return this.endereco; }
public void setEndereco(Endereco endereco) { this.endereco = endereco;
} }
A classe Endereco, por sua vez, deve ser anotada conforme o seguinte trecho:
package com.cursojava.model; // imports
@Entity
@Table (name=”tb_endereco”)
@SequenceGenerator(name=”seq_end”, sequenceName=”seq_end_id”) public class Endereco implements Serializable{
private Long id; private String rua; private Integer numero; private Pessoa pessoa; @Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator=”seq_end”) public Long getId() {
return id; }
public void setId(Long id) { this.id = id; }
@Column(updatable=true, name=”end_rua”, nullable=false, length=30) public String getRua() {
JA VA – F ra m ew or ks e A pl ic aç õe s Co rp or at iv as return this.numero; }
public void setNumero(Integer numero) { this.numero = numero;
}
@OneToOne(mappedBy = “endereco”) public Pessoa getPessoa() {
return this.pessoa; }
public void setPessoa(Pessoa pessoa) { this.pessoa = pessoa; }
}
Por fim, apresentamos um trecho de código usando esta configuração de associação:
Pessoa pessoa = new Pessoa(); pessoa.setNome(“João”);
Endereco endereco = new Endereco(); endereco.setRua(“Rua XV de Novembro”); endereco.setNumero(500);
pessoa.setEndereco(endereco); endereco.setPessoa(pessoa);
Session session = HibernateUtil.getSessionFactory() .openSession();
session.beginTransaction(); session.save(pessoa);
session.getTransaction().commit(); session.close();
No exemplo anterior o passo de preenchimento do atributo da associação deve ser feito para os dois objetos. Deve-se preencher o endereço na Pessoa e também a pessoa no Endereco.