Hibernate.orgCommunity Documentation
Table of Contents
This chapters explores some more complex association mappings.
The following model of the relationship betweenEmployer andEmployee uses an entity class (Employment) to represent the association. You can do this when there might be more than one period of employment for the same two parties. Components are used to model monetary values and employee names.

Here is a possible mapping document:
<hibernate-mapping> <class name="Employer" table="employers"> <id name="id"> <generator> <param name="sequence">employer_id_seq</param> </generator> </id> <property name="name"/> </class> <class name="Employment" table="employment_periods"> <id name="id"> <generator> <param name="sequence">employment_id_seq</param> </generator> </id> <property name="startDate" column="start_date"/> <property name="endDate" column="end_date"/> <component name="hourlyRate"> <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> <param name="sequence">employee_id_seq</param> </generator> </id> <property name="taxfileNumber"/> <component name="name"> <property name="firstName"/> <property name="initial"/> <property name="lastName"/> </component> </class></hibernate-mapping>
Here is the table schema generated bySchemaExport.
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 employersalter table employment_periods add constraint employment_periodsFK1 foreign key (employee_id) references employeescreate sequence employee_id_seqcreate sequence employment_id_seqcreate sequence employer_id_seq
Consider the following model of the relationships betweenWork,Author andPerson. In the example, the relationship betweenWork andAuthor is represented as a many-to-many association and the relationship betweenAuthor andPerson is represented as one-to-one association. Another possibility would be to haveAuthor extendPerson.

The following mapping document correctly represents these relationships:
<hibernate-mapping> <class name="Work" table="works" discriminator-value="W"> <id name="id" column="id"> <generator/> </id> <discriminator column="type" type="character"/> <property name="title"/> <set name="authors" table="author_work"> <key column name="work_id"/> <many-to-many 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/> </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 column="work_id"/> </set> </class> <class name="Person" table="persons"> <id name="id" column="id"> <generator/> </id> <property name="name"/> </class></hibernate-mapping>
There are four tables in this mapping:works,authors andpersons hold work, author and person data respectively.author_work is an association table linking authors to works. Here is the table schema, as generated bySchemaExport:
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 personsalter table author_work add constraint author_workFK0 foreign key (author_id) references authorsalter table author_work add constraint author_workFK1 foreign key (work_id) references works
In this section we consider a model of the relationships betweenCustomer,Order,Line Item andProduct. There is a one-to-many association betweenCustomer andOrder, but how can you representOrder /LineItem /Product? In the example,LineItem is mapped as an association class representing the many-to-many association betweenOrder andProduct. In Hibernate this is called a composite element.

The mapping document will look like this:
<hibernate-mapping> <class name="Customer" table="customers"> <id name="id"> <generator/> </id> <property name="name"/> <set name="orders" inverse="true"> <key column="customer_id"/> <one-to-many/> </set> </class> <class name="Order" table="orders"> <id name="id"> <generator/> </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> <property name="quantity"/> <many-to-one name="product" column="product_id"/> </composite-element> </list> </class> <class name="Product" table="products"> <id name="id"> <generator/> </id> <property name="serialNumber"/> </class></hibernate-mapping>
customers,orders,line_items andproducts hold customer, order, order line item and product data respectively.line_items also acts as an association table linking orders with products.
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 customersalter table line_items add constraint line_itemsFK0 foreign key (product_id) references productsalter table line_items add constraint line_itemsFK1 foreign key (order_id) references orders
These examples are available from the Hibernate test suite. You will find many other useful example mappings there by searching in thetest folder of the Hibernate distribution.
<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><class name="Customer"> <id name="customerId" length="10"> <generator/> </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/> </list></class><class name="Order" table="CustomerOrder" lazy="true"> <synchronize table="LineItem"/> <synchronize table="Product"/> <composite-id name="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/> </bag> </class> <class name="LineItem"> <composite-id name="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/> </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>
<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> <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> <column name="userName"/> <formula>org</formula> </many-to-many> </set></class>
<class name="Person" discriminator-value="P"> <id name="id" column="person_id" unsaved-value="0"> <generator/> </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>
<class name="Person"> <id name="id"> <generator/> </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/> </set> <property name="userId" length="8"/></class><class name="Address"> <id name="id"> <generator/> </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/> </id> <many-to-one name="user" column="userId" property-ref="userId"/> <property name="type" not-null="true"/> </class>