528 lines
17 KiB
XML
528 lines
17 KiB
XML
<chapter id="associations">
|
|
|
|
<title>Mapeos de Asociación</title>
|
|
|
|
<sect1 id="assoc-intro" revision="1">
|
|
<title>Introducción</title>
|
|
|
|
<para>
|
|
Los mapeos de asociación son frecuentemente las cosas mas difíciles
|
|
de hacer correctamente. En esta sección iremos a través de los casos
|
|
canónicos uno a uno, comenzando con los mapeos unidireccionales, y considerando
|
|
luego los casos bidireccionales. Usaremos <literal>Person</literal> y <literal>Address</literal>
|
|
en todos los ejemplos.
|
|
</para>
|
|
|
|
<para>
|
|
Clasificaremos las asociaciones por cuanto mapeen o no a una tabla
|
|
de unión interviniente, y por su multiplicidad.
|
|
</para>
|
|
|
|
<para>
|
|
Las claves foráneas que aceptan valores nulos (en adelante, nullables)
|
|
no son consideradas una buena práctica en el modelado tradicional de datos,
|
|
así que todos nuestros ejemplos usan claves foráneas no nullables.
|
|
Esto no es un requerimiento de Hibernate, y todos los mapeos funcionarán
|
|
si quitas las restricciones de nulabilidad.
|
|
</para>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="assoc-unidirectional" revision="1">
|
|
<title>Asociaciones Unidireccionales</title>
|
|
|
|
<sect2 id="assoc-unidirectional-m21">
|
|
<title>muchos a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación unidireccional muchos-a-uno</emphasis> es el tipo
|
|
más común de asociaciones unidireccionales.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
|
create table Address ( addressId bigint not null primary key )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-unidirectional-121">
|
|
<title>uno a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación unidireccional uno-a-uno en una clave primaria</emphasis>
|
|
es casi idéntica. La única diferencia es la restricción de unicidad
|
|
de la columna.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
|
create table Address ( addressId bigint not null primary key )
|
|
]]></programlisting>
|
|
|
|
<para>
|
|
Usualmente, una <emphasis>asociación unidireccional uno-a-uno en una
|
|
clave primaria</emphasis> usa un generador de id especial. (Observa que hemos
|
|
invertido el sentido de la asociación en este ejemplo).
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key )
|
|
create table Address ( personId bigint not null primary key )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-unidirectional-12m">
|
|
<title>uno a muchos</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación unidireccional uno-a-muchos en una clave foránea</emphasis>
|
|
es un caso muy inusual, y realmente no está recomendada.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key )
|
|
create table Address ( addressId bigint not null primary key, personId bigint not null )
|
|
]]></programlisting>
|
|
|
|
<para>
|
|
Creemos que es mejor usar una tabla de unión para este tipo de asociación.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="assoc-unidirectional-join" revision="1">
|
|
<title>Asociaciones unidireccionales con tablas de unión</title>
|
|
|
|
<sect2 id="assoc-unidirectional-join-12m">
|
|
<title>uno a muchos</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación unidireccional uno-a-muchos en una tabla de unión</emphasis>
|
|
es más preferible. Observa que especificando <literal>unique="true"</literal>, hemos
|
|
cambiado la multiplicidad de muchos-a-muchos a uno-a-muchos.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-unidirectional-join-m21">
|
|
<title>muchos a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación unidireccional muchos-a-uno en una tabla de unión</emphasis>
|
|
es bastante común cuando la asociación es opcional.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-unidirectional-join-121">
|
|
<title>uno a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación unidireccional uno-a-uno en una tabla de unión</emphasis>
|
|
es inusual en extremo, pero posible.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-unidirectional-join-m2m">
|
|
<title>muchos a muchos</title>
|
|
|
|
<para>
|
|
Finalmente, tenemos una <emphasis>asociación unidireccional muchos-a-muchos</emphasis>
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="assoc-bidirectional" revision="1">
|
|
<title>Asociaciones Bidireccionales</title>
|
|
|
|
<sect2 id="assoc-bidirectional-m21">
|
|
<title>uno a muchos / muchos a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación bidireccional muchos-a-uno</emphasis> es
|
|
el tipo más común de asociación. (Esta es la relación
|
|
estándar padre/hijo.)
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key, addressId bigint not null )
|
|
create table Address ( addressId bigint not null primary key )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-bidirectional-121">
|
|
<title>uno a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación bidireccional uno-a-uno en una clave foránea</emphasis>
|
|
es bastante común.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key, addressId bigint not null unique )
|
|
create table Address ( addressId bigint not null primary key )
|
|
]]></programlisting>
|
|
|
|
<para>
|
|
Una <emphasis>asociación bidireccional uno-a-uno en una clave primaria</emphasis>
|
|
usa el generador de id especial.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
create table Person ( personId bigint not null primary key )
|
|
create table Address ( personId bigint not null primary key )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="assoc-bidirectional-join" revision="1">
|
|
<title>Asociaciones bidireccionales con tablas de unión</title>
|
|
|
|
<sect2 id="assoc-bidirectional-join-12m">
|
|
<title>uno a muchos / muchos a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación bidireccional uno-a-muchos en una tabla de unión</emphasis>.
|
|
Observa que el <literal>inverse="true"</literal> puede ir a cualquier lado de la asociación,
|
|
en la colección, o en la unión.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-bidirectional-join-121">
|
|
<title>uno a uno</title>
|
|
|
|
<para>
|
|
Una <emphasis>asociación bidireccional uno-a-uno en una tabla de unión</emphasis>
|
|
es inusual en extremo, pero posible.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<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="address"
|
|
column="personId"
|
|
not-null="true"
|
|
unique="true"/>
|
|
</join>
|
|
</class>]]></programlisting>
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="assoc-bidirectional-join-m2m">
|
|
<title>muchos a muchos</title>
|
|
|
|
<para>
|
|
Finalmente, tenemos una <emphasis>asociación bidireccional muchos-a-muchos</emphasis>.
|
|
</para>
|
|
|
|
<programlisting><![CDATA[<class name="Person">
|
|
<id name="id" column="personId">
|
|
<generator class="native"/>
|
|
</id>
|
|
<set name="addresses">
|
|
<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">
|
|
<key column="addressId"/>
|
|
<many-to-many column="personId"
|
|
class="Person"/>
|
|
</set>
|
|
</class>]]></programlisting>
|
|
|
|
<programlisting><![CDATA[
|
|
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 )
|
|
]]></programlisting>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
|
|
</chapter>
|
|
|