Hibernate.org Community Documentation

- Anterior
- Siguiente

## Capítulo 8. Mapeos de asociación

## 8.1. Introducción

Los mapeos de asociación son frecuentemente lo más difícil de implementar correctamente. En esta sección revisaremos algunos casos canónicos uno por uno, comenzando con los mapeos unidireccionales y luego considerando los casos bidireccionales. Vamos a utilizar `Person` y `Address` en todos los ejemplos.

Vamos a clasificar las asociaciones en cuanto su multiplicidad y a si mapean o no a una tabla de unión interviniente.

Las claves foráneas que aceptan valores nulos no se consideran como una buena práctica en el modelado tradicional de datos, así que todos nuestros ejemplos utilizan claves foráneas no nulas. Esto no es un requisito de Hibernate y todos los mapeos funcionarán si quita las restricciones de nulabilidad.

## 8.2. Asociaciones Unidireccionales

### 8.2.1. Many-to-one

Una asociación unidireccional muchos-a-uno es el tipo de asociación unidireccional más común.

    <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. Uno-a-uno

Una asociación unidireccional uno-a-uno en una clave foránea es casi idéntica. La única diferencia es la restricción de unicidad de la columna.

    <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 )

Usualmente, una asociación unidireccional uno-a-uno en una clave principal utiliza un generador de id especial. Sin embargo, hemos invertido la dirección de la asociación:

    <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. Uno-a-muchos

Una asociación unidireccional uno-a-muchos en una clave foránea es un caso muy inusual y no se recomienda.

    <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 )

En lugar debe utilizar una tabla de unión para esta clase de asociación.

## 8.3. Asociaciones unidireccionales con tablas de unión

### 8.3.1. Uno-a-muchos

Se prefiere una asociación unidireccional uno-a-muchos en una tabla de unión . El especificar `unique="true"`, cambia la multiplicidad de muchos-a-muchos a uno-a-muchos.

    <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. Many-to-one

Una asociación unidireccional muchos-a-uno en una tabla de unión es común cuando la asociación es opcional. Por ejemplo:

    <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. Uno-a-uno

Una asociación unidireccional uno-a-uno en una tabla de unión es extremadamente inusual, pero es posible.

    <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. Muchos-a-muchos

Finalmente, este es un ejemplo de una asociación unidireccional muchos-a-muchos.

    <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. Asociaciones bidireccionales

### 8.4.1. uno-a-muchos / muchos-a-uno

Una asociación bidireccional muchos-a-uno es el tipo de asociación más común. El siguiente ejemplo ilustra la relación estándar padre/hijo.

    <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 )

Si utiliza un `List`, u otra colección con índice, configure la columna `key` de la clave foránea como `not null`. Hibernate administrará la asociación del lado de las colecciones para mantener el índice de cada elemento, haciendo del otro lado virtualmente inverso al establecer `update="false"` y `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

    >

Es importante que defina `not-null="true"` en el elemento `<key>` del mapeo de la colección si la columna de la clave foránea es `NOT NULL`. No declare sólamente `not-null="true"` en un elemento `<column>` posiblemente anidado sino en el elemento `<key>`.

### 8.4.2. Uno-a-uno

Una asociación bidireccional uno-a-uno en una clave foránea es común:

    <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 )

Una asociación bidireccional uno-a-uno en una clave primaria utiliza el generador 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. Asociaciones bidireccionales con tablas de unión

### 8.5.1. uno-a-muchos / muchos-a-uno

El siguiente es un ejemplo de una asociación bidireccional uno-a-muchos en una tabla de unión. El `inverse="true"` puede ir en cualquier lado de la asociación, en la colección, o en la unión.

    <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. uno a uno

Una asociación bidireccional uno-a-uno en una tabla de unión es extremadamente inusual, pero es posible.

    <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. Muchos-a-muchos

Este es un ejemplo de una asociación bidireccional muchos-a-muchos.

    <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. Mapeos de asociación más complejos

Uniones de asociación más complejas son extremadamente raras. Hibernate maneja situaciones más complejas utilizando fragmentos SQL incluidos en el documento de mapeo. Por ejemplo, si una tabla con datos históricos de información de cuenta define las columnas `accountNumber`, `effectiveEndDate` y `effectiveStartDate`, se mapearían así:

    <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"/>

Entonces puede mapear una asociación a la instancia actual, la que tiene `effectiveEndDate` nulo, utilizando:

    <many-to-one name="currentAccountInfo"

            property-ref="currentAccountKey"

            class="AccountInfo">

        <column name="accountNumber"/>

        <formula

    >'1'</formula>

    </many-to-one

    >

En un ejemplo más complejo, imagínese que la asociación entre `Employee` y `Organization` se mantienen en una tabla `Employment` llena de datos históricos de empleo. Entonces se puede mapear una asociación al empleador más reciente del empleado, el que tiene la `startDate` más reciente, de esta manera:

    <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 funcionalidad le permite cierto grado de creatividad y flexibilidad, pero usualmente es más práctico manejar esta clase de casos utilizando HQL o una petición de criterio.

Copyright © 2004 Red Hat, Inc.

- AnteriorCapítulo 7. Mapeos de colección
- Subir
- Inicio
- SiguienteCapítulo 9. Mapeo de componentes