Você está na página 1de 38

Hibernate componentes, herana, e associaes

Jobson Ronan {jrjs@cin.ufpe.br}

Objetivos

Aprender como realizar o mapeamento de modelos entidades que possuem associaes, composies e herana com o hibernate

Granularidade alta (fina)

Fine-grained == mais classes que tabelas

Mais coeso, mais reuso, modelo fcil de entender

Freqentemente o melhor modelo de dados para uma tabela traduzse em mais de uma classe

Considere, por exemplo, uma tabela cliente com dois endereos: endereco_fatura e endereco_entrega, cidade_fatura, cidade_entrega, etc. Uma classe Endereco, agruparia campos relativos ao endereo de um Cliente, que teria propriedades enderecoFatura e enderecoEntrega como referncias para dois objetos da classe Endereco Uma coluna email poderia ser expandida em uma classe Email, para detalhar um tipo de dados e encapsular validao de e-mail em vez de ser uma mera propriedade String do Cliente

Tipos de objetos: entidade ou valor

Um objeto do tipo entidade tem sua prpria identidade de registro de banco de dados

Uma referncia para uma entidade tornada persistente como uma referncia no banco de dados (foreign key) Uma entidade pode existir independentemente de outra entidade Pertence a uma entidade Seu estado persistente parte do registro da entidade que a possui No tm identificadores ou propriedades de identificao O tempo de vida limitado pelo tempo de vida da entidade que o possui Exemplos nativos: Strings, Integers, etc.

Um objeto do tipo valor no tem identidade de banco de dados


Um dos objetos de um registro tem uma identidade prpria; os outros so dependentes dele

No exemplo anterior: objetos do tipo Cliente so entidades, objetos do tipo Endereco e Email so valores dependentes de um Cliente

Componentes

Um componente em Hibernate a parte dependente de um objeto composto entidade-valor

Uma composio ocorre quando uma entidade, que tem identidade na tabela, est associada a objetos de valor que no tm identidade na tabela (seus dados so parte da tabela) A remoo do registro no banco remove a entidade e seus componentes derivados (no confunda com cascade-delete)

Um componente uma propriedade

Meio termo entre uma propriedade de campo de dados (field) e uma propriedade que referncia em relacionamento Componentes s existem como objetos, mas no como tabelas No confunda com componente de software (arquitetura)

Componentes e tabelas

Os atributos do componente esto mapeados mesma tabela que a classe composta

Mapeamento de componentes
<class name="User" table="USER"> <id name="id column="USER_ID type="long"> <generator class="native"/> </id> <property name="username" column="USERNAME" type="string"/> <component name="homeAddress class="Address"> <property name="street" type="string" column="HOME_STREET" not^-null="true"/> <property name="city" type="string" column="HOME_CITY" not-null="true"/> <property name="zipcode" type="short" column="HOME_ZIPCODE" not-null="true"/> </component> <component name="billingAddress class="Address"> <property name="street" type="string" column="BILLING_STREET" not-null="true"/> <property name="city" type="string" column="BILLING_CITY" not-null="true"/> <property name="zipcode" type="short" column="BILLING_ZIPCODE" not-null="true"/> </component> ... </class>

Limitaes de componentes

Classes mapeadas como componentes tm vrias limitaes

No podem ter seus objetos compartilhados (no h como referirse a eles pois no tm identidade prpria) No existe maneira elegante de representar uma referncia nula para um componente ( representado com valores nulos em todas as colunas do componente): se voc gravar um componente no nulo com apenas valores nulos, Hibernate retorna null!

Mapeamento de herana

Herana o descasamento mais visvel entre os mundos relacional e orientado a objetos


Mundo OO possui relacionamento um e tem um Mundo relacional apenas possui relacionamento tem um Uma tabela por classe concreta: modelo relacional ignora herana e polimorfismo Uma tabela por hierarquia de classes: permite polimorfismo com tabelas de-normalizadas mais uma coluna extra contendo informao de tipo Uma tabela por subclasse: representa relacionamentos um atravs de relacionamentos tem um (chave estrangeira)

H vrias estratgias [Ambler 2002]*

Uma tabela por classe concreta

Uma tabela por classe concreta

Ideal para classes que no fazem parte de uma hierarquia ou que esto na raiz de uma hierarquia (nvel mais alto)

Essas classes no devem ser usadas em polimorfismo Uma declarao <class> para cada classe concreta; um atributo table diferente para cada uma (igual a mapeamento simples) Pouco suporte para associaes polimrficas Queries polimrficos, executados em superclasses das classes usadas causam mltiplos queries nas tabelas mapeadas s classes concretas Dificulta evoluo do esquema (mudanas semnticas em propriedades da superclasse afetam colunas de vrias tabelas)

Desvantagens

Queries gerados

Os queries abaixo so conceituais (o SQL real gerado pelo Hibernate pode ser diferente) Dois queries para fazer uma pesquisa na superclasse BillingDetails (ineficiente!)
select CREDIT_CARD_ID, OWNER, NUMBER, CREATED, TYPE, ... from CREDIT_CARD where CREATED = ? select BANK_ACCOUNT_ID, OWNER, NUMBER, CREATED, BANK_NAME, ... from BANK_ACCOUNT where CREATED=?

Para fazer uma pesquisa numa classe concreta


select CREDIT_CARD_ID, TYPE, EXP_MONTH, EXP_YEAR from CREDIT_CARD where CREATED = ?

Uma tabela por hierarquia

Uma tabela por hierarquia

Mapeia-se a hierarquia toda a uma nica tabela

Tabela inclui uma coluna para identificar a classe (tipo); esta coluna (discriminator) no mapeada a uma propriedade mas usada internamente pelo Hibernate H colunas para todas as propriedades de todas as classes da hierarquia A classe raiz mapeada da forma convencional <class> Subclasses so mapeadas dentro de <class> como <subclass> Forma mais eficiente de implementar polimorfismo simples de implementar, entender e evoluir Colunas de propriedades declaradas em subclasses precisam aceitar valores nulos (no pode ser declarada not-null)

Vantagens

Desvantagens

Queries gerados

Exemplo de query polimrfico (conceitual) na superclasse; um s query recupera dados de todas as subclasses
select BILLING_DETAILS_ID, BILLING_DETAILS_TYPE, OWNER, ..., CREDIT_CARD_TYPE, from BILLING_DETAILS where CREATED = ?

Exemplo de um query em uma classe concreta


select BILLING_DETAILS_ID, CREDIT_CARD_TYPE, CREDIT_CARD_EXP_MONTH, ... from BILLING_DETAILS where BILLING_DETAILS_TYPE='CC' and CREATED = ?

Mapeamento
<hibernate-mapping> <class name="BillingDetails" table="BILLING_DETAILS" discriminator-value="BD"> <id name="id" column="BILLING_DETAILS_ID" type="long"> <generator class="native"/> </id>

<discriminator column="BILLING_DETAILS_TYPE" type="string"/>


<property name="name" column="OWNER" type="string"/> ... <subclass name="CreditCard" discriminator-value="CC"> <property name="type" column="CREDIT_CARD_TYPE"/> ... </subclass> ... </class> </hibernate-mapping>

Uma tabela por subclasse

Uma tabela por subclasse

Representa herana como relacionamentos de chave estrangeira

Cada subclasse que declara propriedades persistentes (inclusive interfaces e classes abstratas) tem sua prpria tabela Cada tabela possui colunas apenas para propriedades noherdadas, e uma chave primria que chave estrangeira da superclasse Criao de uma instncia cria registros nas tabelas da superclasse e subclasse A recuperao dos dados realizada atravs de um join das tabelas <joined-subclass> (que pode conter outros elementos <joinedsubclass>) pode ser usada no lugar de ou dentro de <class>

Uma tabela por subclasse

Vantagens

Modelo relacional normalizado Evoluo e restries de integridade simples Novas classes/tabelas criadas sem afetar classes/tabelas existentes Performance baixa em hierarquias complexas Mais difcil de codificar a mo (complicado de integrar com JDBC legado)

Desvantagens

Queries (conceituais) produzidos


Bem mais complicados... Query na superclasse


select BD.BILLING_DETAILS_ID, BD.CREATED, CC.TYPE, ..., BA.BANK_SWIFT, ... case when CC.CREDIT_CARD_ID is not null then 1 when BA.BANK_ACCOUNT_ID is not null then 2 when BD.BILLING_DETAILS_ID is not null then 0 end as TYPE from BILLING_DETAILS BD left join CREDIT_CARD CC on BD.BILLING_DETAILS_ID = CC.CREDIT_CARD_ID left join BANK_ACCOUNT BA on BD.BILLING_DETAILS_ID = BA.BANK_ACCOUNT_ID where BD.CREATED = ?

Query na subclasse
select BD.BILLING_DETAILS_ID, BD.CREATED, CC.TYPE, ... from CREDIT_CARD CC inner join BILLING_DETAILS BD on BD.BILLING_DETAILS_ID = CC.CREDIT_CARD_ID where CC.CREATED = ?

Qual estratgia?

Normalmente, usa-se uma combinao de estratgias

Estratgias assumem desenvolvimento top-down (isto no integrao de um sistema legado)

Se no houver necessidade de queries polimrficos ou associaes, prefira Tabela por Classe Concreta Se houver necessidade de associaes polimrficas, use...

... Tabela por Hierarquia se as classes tiverem poucas propriedades e for uma hierarquia simples ... Tabela por Subclasse se a hierarquia for mais complicada ou classes tiverem muitas propriedades (ou ainda se as restries de Tabela por Hierarquia como nulidade de colunas forem inaceitveis no modelo de dados)

Resumo: tags de mapeamento


<component>

Uma composio (objeto associado dependente)


Usada para implementar a estratgia de mapeamento de herana tabela por hierarquia de classe Usado para implementar a estratgia table-persubclass onde cada subclasse tem sua prpria tabela Coluna e propriedade usada na estratgia tabela por hierarquia de classe para identificar a subclasse

<subclass>

<joined-subclass>

<discriminator>

XML de mapeamento
<?xml version="1.0"?> <hibernate-mapping> <class name="BillingDetails table="BILLING_DETAILS"> <id name="id" column="BILLING_DETAILS_ID" type="long"> <generator class="native"/> </id> <property name="owner" column="OWNER" type="string"/> ... <joined-subclass name="CreditCard" table="CREDIT_CARD"> <key column="CREDIT_CARD_ID"> <property name="type" column="TYPE"/> ... </joined-subclass> ... </class> </hibernate-mapping>

Associaes

Associaes no Hibernate funcionam da mesma maneira que associaes de objetos em Java

Diferente de EJBs CMP, onde relacionamentos so gerenciados pelo container Associaes de objetos em Hibernate so unidirecionais e no so gerenciadas pelo container Algumas so implementadas via colees

Associaes sempre so relacionamentos entre entidades

Associaes um-para-muitos so as mais comuns

Qualquer associao muitos-para-muitos pode ser implementada com um par de associaes um-para-muitos: mais simples! D para realizar quase tudo apenas com <many-to-one>

Multiplicidade de associaes

A primeira classificao que fazemos de uma associao sua multiplicidade Exemplo


H mais de um Lance (Bid) para um certo Item? H mais de um Item para um certo Lance?

Concluso

Existe uma associao de muitos para um de Bid para Item Por ser bidirecional, podemos dizer que tambm existe uma associao de um para muitos de Item para Bid: o item conhece todos os lances feitos para ele.

Uma simples associao

A associao unidirecional, muitos para um de Bid para Item a mais simples possvel

A referncia retornada por Bid.getItem() mapeada coluna ITEM_ID na tabela BID, que chave estrangeira da chave primria da tabela ITEM
<class name="Bid" table="BID"> ... <many-to-one name="item" column="ITEM_ID" class="Item" not-null="true"/> </class>

public class Bid { ... private Item item; public void setItem(Item item) { this.item = item; } public Item getItem() { return item; } ... }

Se houver um lance (bid) o item tem que existir

<many-to-one>

Many-to-one uma associao comum


O modelo relacional many-to-one Uma referncia de objeto many-to-one name e column: nome da propriedade e coluna do banco cascade: pode ter save-update, delete, all (informa que tipo de operao ser repetida no objeto da associao) outer-join: se true, objeto associado carregado junto com o objeto pai; se ausente, o comportamento ocorre se objeto associado no estiver definido como um proxy.

Alguns atributos:

Tornando-a bidirecional

Como encontrar todos os lances para um dado item?

Associao bidirecional um para muitos: use um set!

public class Item { ... private Set bids = new HashSet(); public void setBids(Set bids) { this.bids = bids; } public Set getBids() { return bids; } public void addBid(Bid bid) { <class name="Item" table="ITEM"> bid.setItem(this); ... bids.add(bid); <set name="bids> } <key column="ITEM_ID"/> ... <one-to-many class="Bid"/> }

</set> </class>

<one-to-many>

<set>

Este <set> contm <one-to-many>: uma coleo de registros mapeado diretamente tabela!

Representa uma relao um para muitos no modelo relacional

Mapeamento direto: atributo class informa a classe (no preciso informar colunas nem nome da tabela o mapeamento da classe referida j tem essa informao!)

Um para um

Uma associao um para um pode ser declarada com o elemento <one-to-one> e/ou <many-to-one> H dois tipos de relacionamentos um-para-um

Associaes de chave estrangeira unvocas: a chave nunca se repete na classe associada usa elemento <many-to-one>; usa tambm <one-to-one> se for bidirecional. Associaes de chave primria: os dois objetos compartilham a mesma chave primria usa apenas elementos <one-to-one>

Associao muitos para muitos unidirecional

<class name=Category ...> ... <set name="items" table="CATEGORY_ITEM" lazy="true" cascade="save-update"> <key column="CATEGORY_ID"/> <many-to-many class="Item" column="ITEM_ID"/> </set>

Transaction tx = session.beginTransaction(); Category cat = (Category) session.get(Category.class, categoryId); Item item = (Item) session.get(Item.class, itemId); cat.getItems().add(item); tx.commit();

Muitos para muitos bidirecional


<class name="org.hibernate.auction.Category"> <id name="id" column="ID"/> ... <set name="items" table="CATEGORY_ITEM"> <key column="CATEGORY_ID"/> <many-to-many class="org.hibernate.auction.Item" column="ITEM_ID"/> </set> </class> <class name="org.hibernate.auction.Item"> <id name="id" column="ID"/> ... <!-- inverse end --> <set name="categories" table="CATEGORY_ITEM"> <key column="ITEM_ID"/> <many-to-many class="org.hibernate.auction.Category column="CATEGORY_ID"/> </set> </class>

Uso da associao bidirecional

preciso modificar os dois lados!


Transaction tx = session.beginTransaction(); Category cat = (Category) session.get(Category.class, categoryId); Item item = (Item) session.get(Item.class, itemId); cat.getItems().add(item);

item.getCategories().add(category);
tx.commit();

Associaes polimrficas

Todas as associaes mostradas at agora suportam polimorfismo

No preciso fazer nada de especial para ter polimorfismo no Hibernate

Colees polimrficas: exemplo


<class name=User > ... <set name="billingDetails" lazy="true" cascade="save-update" inverse="true"> <key column="USER_ID"/> <one-to-many class="BillingDetails"/> </set>

CreditCard cc = new CreditCard(); cc.setNumber(ccNumber); cc.setType(ccType); cc.setExpiryDate(ccExpiryDate); Session s = f.openSession(); Transaction tx = s.beginTransaction(); User user = (User) s.get(User.class, uid); // Call convenience method user.addBillingDetails(cc);

<class name=BillingDetails> <many-to-one name="user" class="User" column="USER_ID"/>


Session s = f.openSession(); Transaction tx = s.beginTransaction(); User user = (User) s.get(User.class, uid); Iterator i = user.getBillingDetails().iterator(); while ( i.hasNext() ) { BillingDetails bd = (BillingDetails) i.next(); // CreditCard.pay() or BankAccount.pay() bd.pay(ccPaymentAmount); } tx.commit(); s.close();

tx.commit(); s.close();

Concluses

Hibernate no ajuda s na implementao de modelos simples Hibernate implementa facilmente coisas que levariam semanas Associaes, composies e heranas no so mais problemas para a camada de persistncia

Referncias

Hibernate in Action Hibernate reference manual caveatemptor.hibernate.org

Exerccio 1

Implementar no Hibernate o seguinte modelo

Você também pode gostar