Hibernate.org Community Documentation

- Anterior
- Siguiente

## Capítulo 26. Ejemplo: mapeos varios

Este capítulo explora algunos de los mapeos de asociaciones más complejos.

## 26.1. Empleador/Empleado

El siguiente modelo de la relación entre `Employer` y `Employee` utiliza una clase de entidad (`Employment`) para representar la asociación. Puede hacer esto cuando podría haber más de un período de empleo para los dos mismos participantes. Se utilizan componentes para modelar los valores monetarios y los nombres de los empleados.

He aquí un posible documento de mapeo:

    <hibernate-mapping>

        <class name="Employer" table="employers">

            <id name="id">

                <generator class="sequence">

                    <param name="sequence"

    >employer_id_seq</param>

                </generator>

            </id>

            <property name="name"/>

        </class>

        <class name="Employment" table="employment_periods">

            <id name="id">

                <generator class="sequence">

                    <param name="sequence"

    >employment_id_seq</param>

                </generator>

            </id>

            <property name="startDate" column="start_date"/>

            <property name="endDate" column="end_date"/>

            <component name="hourlyRate" class="MonetaryAmount">

                <property name="amount">

                    <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>

                </property>

                <property name="currency" length="12"/>

            </component>

            <many-to-one name="employer" column="employer_id" not-null="true"/>

            <many-to-one name="employee" column="employee_id" not-null="true"/>

        </class>

        <class name="Employee" table="employees">

            <id name="id">

                <generator class="sequence">

                    <param name="sequence"

    >employee_id_seq</param>

                </generator>

            </id>

            <property name="taxfileNumber"/>

            <component name="name" class="Name">

                <property name="firstName"/>

                <property name="initial"/>

                <property name="lastName"/>

            </component>

        </class>

    </hibernate-mapping

    >

Este es el esquema de tablas generado por `SchemaExport`.

    create table employers (
        id BIGINT not null,
        name VARCHAR(255),
        primary key (id)
    )

    create table employment_periods (
        id BIGINT not null,
        hourly_rate NUMERIC(12, 2),
        currency VARCHAR(12),
        employee_id BIGINT not null,
        employer_id BIGINT not null,
        end_date TIMESTAMP,
        start_date TIMESTAMP,
        primary key (id)
    )

    create table employees (
        id BIGINT not null,
        firstName VARCHAR(255),
        initial CHAR(1),
        lastName VARCHAR(255),
        taxfileNumber VARCHAR(255),
        primary key (id)
    )

    alter table employment_periods
        add constraint employment_periodsFK0 foreign key (employer_id) references employers
    alter table employment_periods
        add constraint employment_periodsFK1 foreign key (employee_id) references employees
    create sequence employee_id_seq
    create sequence employment_id_seq
    create sequence employer_id_seq

## 26.2. Autor/Obra

Considere el siguiente modelo de las relaciones entre `Work`, `Author` y `Person`. En el ejemplo representamos la relación entre `Work` y `Author` como una asociación muchos-a-muchos y la relación entre `Author` y `Person` como una asociación uno-a-uno. Otra posibilidad sería que `Author` extendiera `Person`.

El siguiente documento de mapeo representa estas relaciones de manera correcta:

    <hibernate-mapping>

        <class name="Work" table="works" discriminator-value="W">

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

                <generator class="native"/>

            </id>

            <discriminator column="type" type="character"/>

            <property name="title"/>

            <set name="authors" table="author_work">

                <key column name="work_id"/>

                <many-to-many class="Author" column name="author_id"/>

            </set>

            <subclass name="Book" discriminator-value="B">

                <property name="text"/>

            </subclass>

            <subclass name="Song" discriminator-value="S">

                <property name="tempo"/>

                <property name="genre"/>

            </subclass>

        </class>

        <class name="Author" table="authors">

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

                <!-- The Author must have the same identifier as the Person -->

                <generator class="assigned"/>

            </id>

            <property name="alias"/>

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

            <set name="works" table="author_work" inverse="true">

                <key column="author_id"/>

                <many-to-many class="Work" column="work_id"/>

            </set>

        </class>

        <class name="Person" table="persons">

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

                <generator class="native"/>

            </id>

            <property name="name"/>

        </class>

    </hibernate-mapping

    >

Hay cuatro tablas en este mapeo: `works`, `authors` y `persons` tienen los datos de obra, autor y persona respectivamente. `author_work` es una tabla de asociación enlazando los autores a las obras. Este es el esquema de tablas, tal como fue generado por `SchemaExport`:

    create table works (
        id BIGINT not null generated by default as identity,
        tempo FLOAT,
        genre VARCHAR(255),
        text INTEGER,
        title VARCHAR(255),
        type CHAR(1) not null,
        primary key (id)
    )

    create table author_work (
        author_id BIGINT not null,
        work_id BIGINT not null,
        primary key (work_id, author_id)
    )

    create table authors (
        id BIGINT not null generated by default as identity,
        alias VARCHAR(255),
        primary key (id)
    )

    create table persons (
        id BIGINT not null generated by default as identity,
        name VARCHAR(255),
        primary key (id)
    )

    alter table authors
        add constraint authorsFK0 foreign key (id) references persons
    alter table author_work
        add constraint author_workFK0 foreign key (author_id) references authors
    alter table author_work
        add constraint author_workFK1 foreign key (work_id) references works

## 26.3. Cliente/Orden/Producto

En esta sección consideramos un modelo de las relaciones entre `Customer`, `Order`, `Line Item` y `Product`. Hay una asociación uno-a-muchos entre `Customer` y `Order`, pero, ¿cómo deberíamos representar `Order` / `LineItem` / `Product`? En el ejemplo, `LineItem` se mapea como una clase de asociación representando la asociación muchos-a-muchos entre `Order` y `Product`. En Hibernate, esto se llama un elemento compuesto.

El documento de mapeo se verá así:

    <hibernate-mapping>

        <class name="Customer" table="customers">

            <id name="id">

                <generator class="native"/>

            </id>

            <property name="name"/>

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

                <key column="customer_id"/>

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

            </set>

        </class>

        <class name="Order" table="orders">

            <id name="id">

                <generator class="native"/>

            </id>

            <property name="date"/>

            <many-to-one name="customer" column="customer_id"/>

            <list name="lineItems" table="line_items">

                <key column="order_id"/>

                <list-index column="line_number"/>

                <composite-element class="LineItem">

                    <property name="quantity"/>

                    <many-to-one name="product" column="product_id"/>

                </composite-element>

            </list>

        </class>

        <class name="Product" table="products">

            <id name="id">

                <generator class="native"/>

            </id>

            <property name="serialNumber"/>

        </class>

    </hibernate-mapping

    >

`customers`, `orders`, `line_items` y `products` tienen los datos de cliente, orden, ítem de línea de orden y producto respectivamente. Además `line_items` también actúa como una tabla de asociación enlazando órdenes con productos.

    create table customers (
        id BIGINT not null generated by default as identity,
        name VARCHAR(255),
        primary key (id)
    )

    create table orders (
        id BIGINT not null generated by default as identity,
        customer_id BIGINT,
        date TIMESTAMP,
        primary key (id)
    )

    create table line_items (
        line_number INTEGER not null,
        order_id BIGINT not null,
        product_id BIGINT,
        quantity INTEGER,
        primary key (order_id, line_number)
    )

    create table products (
        id BIGINT not null generated by default as identity,
        serialNumber VARCHAR(255),
        primary key (id)
    )

    alter table orders
        add constraint ordersFK0 foreign key (customer_id) references customers
    alter table line_items
        add constraint line_itemsFK0 foreign key (product_id) references products
    alter table line_items
        add constraint line_itemsFK1 foreign key (order_id) references orders

## 26.4. Mapeos varios de ejemplo

Estos ejemplos están disponibles en la suite de pruebas de Hibernate. Allí encontrará muchos otros mapeos de ejemplos útiles en la carpeta `test` de la distribución de Hibernate.

### 26.4.1. Asociación uno-a-uno "Tipificada"

    <class name="Person">

        <id name="name"/>

        <one-to-one name="address"

                cascade="all">

            <formula

    >name</formula>

            <formula

    >'HOME'</formula>

        </one-to-one>

        <one-to-one name="mailingAddress"

                cascade="all">

            <formula

    >name</formula>

            <formula

    >'MAILING'</formula>

        </one-to-one>

    </class>

    <class name="Address" batch-size="2"

            check="addressType in ('MAILING', 'HOME', 'BUSINESS')">

        <composite-id>

            <key-many-to-one name="person"

                    column="personName"/>

            <key-property name="type"

                    column="addressType"/>

        </composite-id>

        <property name="street" type="text"/>

        <property name="state"/>

        <property name="zip"/>

    </class

    >

### 26.4.2. Ejemplo de clave compuesta

    <class name="Customer">

        <id name="customerId"

            length="10">

            <generator class="assigned"/>

        </id>

        <property name="name" not-null="true" length="100"/>

        <property name="address" not-null="true" length="200"/>

        <list name="orders"

                inverse="true"

                cascade="save-update">

            <key column="customerId"/>

            <index column="orderNumber"/>

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

        </list>

    </class>

    <class name="Order" table="CustomerOrder" lazy="true">

        <synchronize table="LineItem"/>

        <synchronize table="Product"/>

        <composite-id name="id"

                class="Order$Id">

            <key-property name="customerId" length="10"/>

            <key-property name="orderNumber"/>

        </composite-id>

        <property name="orderDate"

                type="calendar_date"

                not-null="true"/>

        <property name="total">

            <formula>

                ( select sum(li.quantity*p.price)

                from LineItem li, Product p

                where li.productId = p.productId

                    and li.customerId = customerId

                    and li.orderNumber = orderNumber )

            </formula>

        </property>

        <many-to-one name="customer"

                column="customerId"

                insert="false"

                update="false"

                not-null="true"/>

        <bag name="lineItems"

                fetch="join"

                inverse="true"

                cascade="save-update">

            <key>

                <column name="customerId"/>

                <column name="orderNumber"/>

            </key>

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

        </bag>

    </class>

    <class name="LineItem">

        <composite-id name="id"

                class="LineItem$Id">

            <key-property name="customerId" length="10"/>

            <key-property name="orderNumber"/>

            <key-property name="productId" length="10"/>

        </composite-id>

        <property name="quantity"/>

        <many-to-one name="order"

                insert="false"

                update="false"

                not-null="true">

            <column name="customerId"/>

            <column name="orderNumber"/>

        </many-to-one>

        <many-to-one name="product"

                insert="false"

                update="false"

                not-null="true"

                column="productId"/>

    </class>

    <class name="Product">

        <synchronize table="LineItem"/>

        <id name="productId"

            length="10">

            <generator class="assigned"/>

        </id>

        <property name="description"

            not-null="true"

            length="200"/>

        <property name="price" length="3"/>

        <property name="numberAvailable"/>

        <property name="numberOrdered">

            <formula>

                ( select sum(li.quantity)

                from LineItem li

                where li.productId = productId )

            </formula>

        </property>

    </class

    >

### 26.4.3. Muchos-a-muchos con atributo compartido de clave compuesta

    <class name="User" table="`User`">

        <composite-id>

            <key-property name="name"/>

            <key-property name="org"/>

        </composite-id>

        <set name="groups" table="UserGroup">

            <key>

                <column name="userName"/>

                <column name="org"/>

            </key>

            <many-to-many class="Group">

                <column name="groupName"/>

                <formula

    >org</formula>

            </many-to-many>

        </set>

    </class>

    <class name="Group" table="`Group`">

        <composite-id>

            <key-property name="name"/>

            <key-property name="org"/>

        </composite-id>

        <property name="description"/>

        <set name="users" table="UserGroup" inverse="true">

            <key>

                <column name="groupName"/>

                <column name="org"/>

            </key>

            <many-to-many class="User">

                <column name="userName"/>

                <formula

    >org</formula>

            </many-to-many>

        </set>

    </class>

### 26.4.4. Discriminación basada en contenido

    <class name="Person"

        discriminator-value="P">

        <id name="id"

            column="person_id"

            unsaved-value="0">

            <generator class="native"/>

        </id>

        <discriminator

            type="character">

            <formula>

                case

                    when title is not null then 'E'

                    when salesperson is not null then 'C'

                    else 'P'

                end

            </formula>

        </discriminator>

        <property name="name"

            not-null="true"

            length="80"/>

        <property name="sex"

            not-null="true"

            update="false"/>

        <component name="address">

            <property name="address"/>

            <property name="zip"/>

            <property name="country"/>

        </component>

        <subclass name="Employee"

            discriminator-value="E">

                <property name="title"

                    length="20"/>

                <property name="salary"/>

                <many-to-one name="manager"/>

        </subclass>

        <subclass name="Customer"

            discriminator-value="C">

                <property name="comments"/>

                <many-to-one name="salesperson"/>

        </subclass>

    </class

    >

### 26.4.5. Asociaciones sobre claves alternativas

    <class name="Person">

        <id name="id">

            <generator class="hilo"/>

        </id>

        <property name="name" length="100"/>

        <one-to-one name="address"

            property-ref="person"

            cascade="all"

            fetch="join"/>

        <set name="accounts"

            inverse="true">

            <key column="userId"

                property-ref="userId"/>

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

        </set>

        <property name="userId" length="8"/>

    </class>

    <class name="Address">

        <id name="id">

            <generator class="hilo"/>

        </id>

        <property name="address" length="300"/>

        <property name="zip" length="5"/>

        <property name="country" length="25"/>

        <many-to-one name="person" unique="true" not-null="true"/>

    </class>

    <class name="Account">

        <id name="accountId" length="32">

            <generator class="uuid"/>

        </id>

        <many-to-one name="user"

            column="userId"

            property-ref="userId"/>

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

    </class

    >

Copyright © 2004 Red Hat, Inc.

- AnteriorCapítulo 25. Ejemplo: Aplicación de Weblog
- Subir
- Inicio
- SiguienteCapítulo 27. Prácticas recomendadas