Hibernate.org Community Documentation

- Anterior
- Próxima

## Capítulo 8. Mapeamento de associações

## 8.1. Introdução

Os mapeamentos de associações são, geralmente, os mais difíceis de se acertar. Nesta seção nós examinaremos pelos casos canônicos um por um, começando com mapeamentos unidirecionais e considerando os casos bidirecionais. Usaremos `Person` e `Address` em todos os exemplos.

Classificaremos as associações pela sua multiplicidade e se elas mapeiam ou não uma intervenção na tabela associativa.

O uso de chaves externas anuláveis não é considerado uma boa prática na modelagem de dados tradicional, assim todos os nossos exemplos usam chaves externas anuláveis. Esta não é uma exigência do Hibernate, e todos os mapeamentos funcionarão se você remover as restrições de anulabilidade.

## 8.2. Associações Unidirecionais

### 8.2.1. Muitos-para-um

Uma associação unidirecional muitos-para-um é o tipo mais comum de associação unidirecional.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <many-to-one name="address"

            column="addressId"

            not-null="true"/>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key, addressId bigint not null )
    create table Address ( addressId bigint not null primary key )

### 8.2.2. Um-para-um

Uma associação unidirecional um-para-um em uma chave externa é quase idêntica. A única diferença é a restrição única na coluna.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <many-to-one name="address"

            column="addressId"

            unique="true"

            not-null="true"/>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key, addressId bigint not null unique )
    create table Address ( addressId bigint not null primary key )

Uma associação unidirecional um-para-um na chave primária geralmente usa um gerador de id especial. Note que nós invertemos a direção da associação nesse exemplo.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

    </class>

    <class name="Address">

        <id name="id" column="personId">

            <generator class="foreign">

                <param name="property"

    >person</param>

            </generator>

        </id>

        <one-to-one name="person" constrained="true"/>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table Address ( personId bigint not null primary key )

### 8.2.3. Um-para-muitos

Uma associação unidirecional um-para-muitos em uma chave externa é um caso muito incomum, e realmente não é recomendada.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <set name="addresses">

            <key column="personId"

                not-null="true"/>

            <one-to-many class="Address"/>

        </set>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table Address ( addressId bigint not null primary key, personId bigint not null )

Acreditamos ser melhor usar uma tabela associativa para este tipo de associação.

## 8.3. Associações Unidirecionais com tabelas associativas

### 8.3.1. Um-para-muitos

Uma associação um-para-muitos unidirecional usando uma tabela associativa é o mais comum. Note que se especificarmos `unique="true"`, estaremos modificando a multiplicidade de muitos-para-muitos para um-para-muitos.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <set name="addresses" table="PersonAddress">

            <key column="personId"/>

            <many-to-many column="addressId"

                unique="true"

                class="Address"/>

        </set>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId not null, addressId bigint not null primary key )
    create table Address ( addressId bigint not null primary key )

### 8.3.2. Muitos-para-um

Uma associação unidirecional muitos-para-um em uma tabela associativa é bastante comum quando a associação for opcional.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <join table="PersonAddress"

            optional="true">

            <key column="personId" unique="true"/>

            <many-to-one name="address"

                column="addressId"

                not-null="true"/>

        </join>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
    create table Address ( addressId bigint not null primary key )

### 8.3.3. Um-para-um

Uma associação unidirecional um-para-um em uma tabela associativa é extremamente incomum, mas possível.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <join table="PersonAddress"

            optional="true">

            <key column="personId"

                unique="true"/>

            <many-to-one name="address"

                column="addressId"

                not-null="true"

                unique="true"/>

        </join>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
    create table Address ( addressId bigint not null primary key )

### 8.3.4. Muitos-para-muitos

Finalmente, nós temos a associação unidirecional muitos-para- muitos.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <set name="addresses" table="PersonAddress">

            <key column="personId"/>

            <many-to-many column="addressId"

                class="Address"/>

        </set>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
    create table Address ( addressId bigint not null primary key )

## 8.4. Associações Bidirecionais

### 8.4.1. Um-para-muitos/muitos-para-um

Uma associação bidirecional muitos-para-um é o tipo mais comum de associação. A seguinte amostra ilustra o relacionamento padrão pai/filho. )

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <many-to-one name="address"

            column="addressId"

            not-null="true"/>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

        <set name="people" inverse="true">

            <key column="addressId"/>

            <one-to-many class="Person"/>

        </set>

    </class

    >

    create table Person ( personId bigint not null primary key, addressId bigint not null )
    create table Address ( addressId bigint not null primary key )

Se você usar uma `List` ou outra coleção indexada, você precisará especificar a coluna `key` da chave externa como `not null`. O Hibernate administrará a associação do lado da coleção para que seja mantido o índice de cada elemento da coleção (fazendo com que o outro lado seja virtualmente inverso ajustando `update="false"` e `insert="false"`):

    <class name="Person">

       <id name="id"/>

       ...

       <many-to-one name="address"

          column="addressId"

          not-null="true"

          insert="false"

          update="false"/>

    </class>

    <class name="Address">

       <id name="id"/>

       ...

       <list name="people">

          <key column="addressId" not-null="true"/>

          <list-index column="peopleIdx"/>

          <one-to-many class="Person"/>

       </list>

    </class

    >

Caso uma coluna chave externa adjacente for `NOT NULL`, é importante que você defina `not-null="true"` no elemento `<key>` no mapeamento na coleção se a coluna de chave externa para `NOT NULL`. Não declare como `not-null="true"` apenas um elemento aninhado `<column>`, mas sim o elemento `<key>`.

### 8.4.2. Um-para-um

Uma associação bidirecional um para um em uma chave externa é bastante comum:

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <many-to-one name="address"

            column="addressId"

            unique="true"

            not-null="true"/>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

       <one-to-one name="person"

            property-ref="address"/>

    </class

    >

    create table Person ( personId bigint not null primary key, addressId bigint not null unique )
    create table Address ( addressId bigint not null primary key )

Uma associação bidirecional um para um em uma chave primária usa um gerador de id especial:

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <one-to-one name="address"/>

    </class>

    <class name="Address">

        <id name="id" column="personId">

            <generator class="foreign">

                <param name="property"

    >person</param>

            </generator>

        </id>

        <one-to-one name="person"

            constrained="true"/>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table Address ( personId bigint not null primary key )

## 8.5. Associações Bidirecionais com tabelas associativas

### 8.5.1. Um-para-muitos/muitos-para-um

Segue abaixo uma amostra da associação bidirecional um para muitos em uma tabela de união. Veja que `inverse="true"` pode ser colocado em qualquer ponta da associação, na coleção, ou na união.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <set name="addresses"

            table="PersonAddress">

            <key column="personId"/>

            <many-to-many column="addressId"

                unique="true"

                class="Address"/>

        </set>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

        <join table="PersonAddress"

            inverse="true"

            optional="true">

            <key column="addressId"/>

            <many-to-one name="person"

                column="personId"

                not-null="true"/>

        </join>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
    create table Address ( addressId bigint not null primary key )

### 8.5.2. Um para um

Uma associação bidirecional um-para-um em uma tabela de união é algo bastante incomum, mas possível.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <join table="PersonAddress"

            optional="true">

            <key column="personId"

                unique="true"/>

            <many-to-one name="address"

                column="addressId"

                not-null="true"

                unique="true"/>

        </join>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

        <join table="PersonAddress"

            optional="true"

            inverse="true">

            <key column="addressId"

                unique="true"/>

            <many-to-one name="person"

                column="personId"

                not-null="true"

                unique="true"/>

        </join>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
    create table Address ( addressId bigint not null primary key )

### 8.5.3. Muitos-para-muitos

Finalmente, nós temos uma associação bidirecional de muitos para muitos.

    <class name="Person">

        <id name="id" column="personId">

            <generator class="native"/>

        </id>

        <set name="addresses" table="PersonAddress">

            <key column="personId"/>

            <many-to-many column="addressId"

                class="Address"/>

        </set>

    </class>

    <class name="Address">

        <id name="id" column="addressId">

            <generator class="native"/>

        </id>

        <set name="people" inverse="true" table="PersonAddress">

            <key column="addressId"/>

            <many-to-many column="personId"

                class="Person"/>

        </set>

    </class

    >

    create table Person ( personId bigint not null primary key )
    create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
    create table Address ( addressId bigint not null primary key )

## 8.6. Mapeamento de associações mais complexas

Uniões de associações mais complexas são extremamente raras. O Hibernate possibilita o tratamento de mapeamentos mais complexos, usando fragmentos de SQL embutidos no documento de mapeamento. Por exemplo, se uma tabela com informações de dados históricos de uma conta define as colunas `accountNumber`, `effectiveEndDate` e `effectiveStartDate`, mapeadas assim como segue:

    <properties name="currentAccountKey">

        <property name="accountNumber" type="string" not-null="true"/>

        <property name="currentAccount" type="boolean">

            <formula

    >case when effectiveEndDate is null then 1 else 0 end</formula>

        </property>

    </properties>

    <property name="effectiveEndDate" type="date"/>

    <property name="effectiveStateDate" type="date" not-null="true"/>

Então nós podemos mapear uma associação para a instância atual, aquela com `effectiveEndDate` nulo, usando:

    <many-to-one name="currentAccountInfo"

            property-ref="currentAccountKey"

            class="AccountInfo">

        <column name="accountNumber"/>

        <formula

    >'1'</formula>

    </many-to-one

    >

Em um exemplo mais complexo, imagine que a associação entre `Employee` e `Organization` é mantida em uma tabela `Employment` cheia de dados históricos do trabalho. Então a associação do funcionário mais recentemente e empregado, aquele com a mais recente `startDate`, deve ser mapeado desta maneira:

    <join>

        <key column="employeeId"/>

        <subselect>

            select employeeId, orgId

            from Employments

            group by orgId

            having startDate = max(startDate)

        </subselect>

        <many-to-one name="mostRecentEmployer"

                class="Organization"

                column="orgId"/>

    </join

    >

Esta funcionalidade permite um grau de criatividade e flexibilidade, mas geralmente é mais prático tratar estes tipos de casos, usando uma pesquisa HQL ou uma pesquisa por critério.

Copyright © 2004 Red Hat, Inc.

- AnteriorCapítulo 7. Mapeamento de coleção
- Acima
- Principal
- PróximaCapítulo 9. Mapeamento de Componentes