300 likes | 379 Views
Caio Nakashima caio.nakashima@mds.gov.br caionakashima@gmail.com. Hibernate Associação. Classe pessoa. import java.util.Calendar; public class Pessoa { private Long id; private Calendar dataNascimento; private String nome; private char sexo;
E N D
Caio Nakashima caio.nakashima@mds.gov.br caionakashima@gmail.com Hibernate Associação
Classe pessoa import java.util.Calendar; public class Pessoa { private Long id; private Calendar dataNascimento; private String nome; private char sexo; /** Creates a new instance of Pessoa */ public Pessoa() {} public Long getId() { return id; } private void setId(Long pId) { this.id = pId; } public Calendar getDataNascimento() { return dataNascimento; } public void setDataNascimento (Calendar pData){ this.dataNascimento = pData; } // ... Métodos get e set }
Arquivo de mapeamento Person.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="Pessoa" table="PESSOA"> <id name="id" column="PES_ID"> <generator class="sequence"/> </id> <property name="dataNascimento" column="PES_DATANASC"/> <property name="nome" column="PES_NOME" not-null="true"/> <property name="sexo" column="PES_SEXO"/> </class> </hibernate-mapping>
Arquivo de mapeamento hibernate • Adicionar novo mapeamento para a configuração do Hibernate (hibernate.cfg.xml) <mapping resource="Event.hbm.xml"/> <mapping resource="Pessoa.hbm.xml"/>
Associação entre duas entidades • Será criada associação entre duas entidades. • Pessoas podem participar de eventos e eventos podem ter participantes. • As questões de projeto para serem gerenciados são: • Direção, multiplicidade e comportamento de coleção
Uma associação unidirecional • Será adicionados eventos para a classe Pessoa. • Por este caminho é possível navegar para os eventos para uma pessoa em particular, sem executar uma consulta explícita chamando o método aPessoa.getEvents(). • Será adicionado uma coleção de eventos para a classePessoa. • Pode-se utilizar uma coleção Java (SET), porque a coleção não contem elementos duplicados e a ordem não é relevante. • Assim será projetada uma associação unidirecional multi-valorado, implementado com um SET.
Alteração da classe Pessoa.java public class Pessoa { // Associando a um conjunto de eventos. private Set events = new HashSet(); public Set getEvents() { return events; } public void setEvents(Set events) { this.events = events; } }
Para pensar • Antes de mapear esta associação, uma pequena reflexão. • Esta é uma associação unidirecional. • Pode-se criar outra coleção na classe Event, se desejar navegar de forma bi-direcional, Event.getParticipants(). • Esta escolha de projeto fica a cargo do projetista, que é claro nesta discussão de multiplicidade da associação, uma associação de muitos para muitos.
Hibernate's many-to-many mapping: <hibernate-mapping> <class name="Pessoa" table="PESSOA"> <id name="id" column="PES_ID"> <generator class="sequence"/> </id> <property name="dataNascimento" column="PES_DATANASC"/> <property name="nome" column="PES_NOME" not-null="true"/> <property name="sexo" column="PES_SEXO"/> <set name="events" table="PESSOA_EVENT"> <key column="PES_ID"/> <many-to-many column="EVENT_ID" class="Event"/> </set> </class> </hibernate-mapping>
Tipos de Mapeamento • Hibernate suporta todos os tipos de mapeamento de coleções, um <set> é o mais comum. • Para uma associação de muitos-para-muitos (ou uma relações entre entidades n:m), uma associação entre tabelas é necessária. • Cada linha desta tabela representa uma ligação entre uma pessoa e um evento. • O nome da tabela é configurado com o atributo da tabela de um conjunto de elementos. • O identificador no nome da coluna em uma associação, para o lado da pessoa é definido com o elemento <key>, o nome da coluna para o lado do evento com o atriburo coluna de <many-to-many>. • É necessário informar o Hibernate a classe de objetos na coleção (a classe de outro lado da referência).
Events event_id (PK) event_date title Pessoa-Event event_id pes_id Pessoa pes_id nome sexo datanasc Mapeamento do Esquema
Trabalhando com associação • Novo método em Main.java para associar pessoas a eventos. try{ sf = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory(); Session session = sf.openSession(); //Abre sessão Transaction tx = session.beginTransaction(); //Cria transação //Busca uma pessoa Long pes_id = new Long(2); Pessoa pessoa = (Pessoa) session.get(Pessoa.class, pes_id); System.out.println("Pessoa "+pessoa.getNome()); //Busca uma evento Long event_id = new Long(1); Event evento = (Event) session.load(Event.class, event_id); System.out.println("Evento "+evento.getTitle()); pessoa.getEvents().add(evento); tx.commit(); //Fecha transação session.close(); //Fecha sessão }
load() X get() • http://forum.hibernate.org/viewtopic.php?p=2387456 • O método load() é mais antigo que o método get(). • Se o método load() não encontrar o objeto no cache ou banco de dados uma exceção é gerada. • O método load() nunca retorna NULL. O método get() retorna NULL se o objeto não for encontrado. • Depois de carregar uma Pessoa (pessoa) e um Evento (event), adiciona-se o evento para a pessoa. • Não existe comando explícito de UPDATE() ou SAVE().
automatic dirty checking • Hibernate detecta automaticamente a coleção que foi modificado e a necessidade de ser salvo. • Isto é denominado automatic dirty checking, e pode-se observar isto também tentando modificar o nome e data de qualquer objeto. • Como os dados estão em estado de persistência, Hibernate monitora qualquer mudança e executa SQL em background. • O processo de sincronização do estado da memória com o banco de dados, termina com a finalização da unidade de trabalho. Este processo é denominado FLUSHING.
Persistência • Pode-se carregar um pessoa ou evento para uma diferente unidade de trabalho. • Pode-se modificar um objeto fora de uma seção, quando não está em estado de persistência (se tiver sido persistido antes da seção ser chamada).
Associação • O exemplo apresentado foi de uma associação entre duas classes com mesmo grau de importância, duas entidades. • Existem outras classes e tipos que podem ser classificados como “menos importantes”. • Denomina-se estas classes do tipo valores (value types) e suas instâncias dependem de uma entidade em particular. • As instâncias destes tipos não possuem sua própria entidade, nem são divididos entre entidades. • Os tipos de valores não podem ser encontrado somente no JDK, mas podem também ser escritos dependentes da classe, Endereço ou Saldo, etc. • Hibernate considera todos os tipos do JDK como tipo de valores.
Coleção de valores • Adiciona-se uma coleção de tipos de valores para uma entidade Pessoa. • Deseja-se armazenar endereço de email, assim o tipo utilizado é String e a coleção é novamente um Set. private Set email = new HashSet(); public Set getEmail () { return email; } public void setEmail (Set email) { this.email = email; } • Mapeamento <set name="email" table=“PESSOA_EMAIL"> <key column="PES_ID"/> <element type="string" column="EMAIL"/> </set>
A diferença comparando com o mapeamento anterior é um elemento a parte, que especifica o Hibernate que a coleção não contém referência a outra entidade, mas uma coleção de elementos do tipo String (o nome em letras minúsculas especifica um mapeamento Hibernate tipo/conversão). • Novamente, o atributo <table> de um conjunto de elementos do nome da tabela para a coleção. • O elemento <key> define a coluna de chave estrangeira da tabela de coleção. • A coluna <attribute> define o nome da coluna onde os valores String estão armazenados.
Events event_id (PK) event_date title Pessoa-evento event_id pess_id Pessoa pes_id nome datanasc sexo Pessoa_email pess_id email Esquema com a tabela EMAIL
A chave primária da tabela é composta pelos valores das duas colunas (pess_id, email). • Isto implica que não pode ser duplicado email por pessoa, que é exatamente a semântica necessária para um conjunto em Java. • Exercício: • Inserir elementos nesta coleção. • Tentar repetir email para a mesma pessoa.
Associação Bi direcional • O exemplo de associação bi-direcional será entre pessoa (Pessoa) e trabalho no evento. • O esquema do banco de dados não muda, ainda existirá a multiplicidade de muitos-para-muitos. • Um banco de dados é mais flexível que uma linguagem de programação distribuída • Não necessita nada como uma direção de navegação • Dados podem ser visualizados e recuperados em qualquer caminho possível.
Coleção de participantes do evento private Set participants = new HashSet(); public Set getParticipants() { return participants; } public void setParticipants(Set participants) { this.participants = participants; } • Coleção de participantes do evento <set name="participants" table="PESSOA_EVENT" lazy="true" inverse="false"> <key column="EVENT_ID"/> <many-to-many column="PERSON_ID" class="Person"/> </set>
inverse • Esse atributo é utilizado para que o Hibernate saiba como tratar a associação entre duas tabelas. • Quando um lado da associação define o atributo inverse como true, indica que a ligação do relacionamento entre a associação será de responsabilidade do "outro lado" da associação. • Se o atributo inverse não for definido como true, o Hibernate não tem como saber qual dos dois lados foi atualizado, ou seja, vai sempre atualizar os dois lados de uma vez, uma atualização para cada classe da relação, o que seria desnecessário. • Caso contrário, o Hibernate passa a saber de qual lado fazer a atualização e fazendo uma única vez.
lazy • Considerando o problema: • quando se realiza uma consulta (select) em um objeto Pessoa implica em serem feitos n (quantidade de emails da Pessoa) outras consultas para buscar os seus emails. • A resolução do problema pode ser feita apenas definindo o atributo lazy como sendo true. A coleção de centros passa a ser lazy-loading, o que significa que somente será recuperada quando solicitada, ou seja, a coleção de emails de uma Pessoa só seria solicitada caso o programador a acesse através da chamada ao método getEmail().
Mapeamento n-1 <many-to-one name="propertyName" class="ClassName" column="column_name" fetch="join|select" update="true|false" lazy="true|false" insert="true|false" cascade="all|none|save-update|delete“ />
Atributos do mapeamento n-1 • name: nome do atributo na classe Java; • column: coluna do banco de dados. É uma chave estrangeira; • class: nome da classe Java da entidade relacionada; • insert e update: indica se o atributo será incluído e alterado ou somente lido; • fetch: se definido como join é usado para realizar joins sem restrição de nulidade (outer-join). Se for select, um novo select é feito para recuperar a informação da associação. • lazy: se igual a true, o objeto só será recuperado se solicitado; se igual a false, o objeto sempre será recuperado.
cascade indica com que ação em cascata o relacionamento será tratado • none: associação é ignorada; • save-update:os objetos associados vão ser inseridos ou atualizados automaticamente quando o objeto "pai" for inserido ou atualizado; • delete: os objetos associados ao objeto "pai" vão ser deletados; • all: junção de delete e save-update; • all-delete-orphan: o mesmo que all, mas o Hibernate deleta qualquer objeto que tiver sido retirado da associação; • delete-orphan: se o objeto não fizer mais parte da associação, ele removido.
fetch: se definido como join é usado para realizar joins sem restrição de nulidade (outer-join). Se for select, um novo select é feito para recuperar a informação da associação. • lazy: se igual a true, o objeto só será recuperado se solicitado; se igual a false, o objeto sempre será recuperado.
Entidade Criar Inser. Excl. Alter. Listar Event Sim Sim Sim Sim + pessoas Pessoas Sim Sim Sim Sim + email + tel Pessoa_email Sim Sim Sim Sim + pessoas Pessoa_telefones Sim Sim Sim Sim Palestras Sim Sim Sim Sim + pessoas Exercício • Considerando do Diagrama da próxima transparência e utilizando a camada de persistência Hibernate elaborar um conjunto de arquivos necessários para criar as tabelas, inserir, alterar, excluir e listar os registros das seguintes entidades:
Events event_id (PK) event_date title Pessoa pes_id nome datanasc sexo Palestra palestra_id tema titulo Pessoa_telefones pess_id telefone Tipo (celular, Residencial, etc.) Pessoa_email pess_id email Exercício n n 1 n n 1 1 n n n