0% found this document useful (0 votes)
72 views

Chapter 7. Association Mappings Chapter 7. Association Mappings

This document discusses different types of association mappings in Hibernate, including unidirectional and bidirectional mappings. It provides examples of mapping common associations like one-to-one, one-to-many, and many-to-one using foreign keys or join tables. The examples demonstrate how to configure the mapping in Hibernate XML files and the corresponding database tables.

Uploaded by

PRABHU SORTUR
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
72 views

Chapter 7. Association Mappings Chapter 7. Association Mappings

This document discusses different types of association mappings in Hibernate, including unidirectional and bidirectional mappings. It provides examples of mapping common associations like one-to-one, one-to-many, and many-to-one using foreign keys or join tables. The examples demonstrate how to configure the mapping in Hibernate XML files and the corresponding database tables.

Uploaded by

PRABHU SORTUR
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Chapter 7.

Association Mappings
Prev  Next

Chapter 7. Association Mappings

7.1. Introduction
Association mappings are the often most difficult thing to get right. In this section we'll
go through the canonical cases one by one, starting with unidirectional mappings, and
then considering the bidirectional cases. We'll
We'll use Person and Address in all the
examples.

We'll classify associations by whether or not they map to an intervening join table, and by
multiplicity.

 Nullable foreign keys are not considered good practice in traditional data modelling, so
all our examples use not null foreign keys. This is not a requirement of Hibernate, and the
mappings will all work if you drop the nullability constraints.

7.2. Unidirectional associations


7.2.1. many to one

A unidirectional many-to-one association is the most common kind of unidirectional


association.

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

7.2.2. one to one


A unidirectional one-to-one association on a foreign key is almost identical. The only
difference is the column unique constraint.

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

A unidirectional one-to-one association on a primary key usually uses a special id


generator. (Notice that we've reversed the direction of the association in this example.)

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

7.2.3. one to many

A unidirectional one-to-many association on a foreign key is a very unusual case, and is


not really recommended.

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

We think it's better to use a join table for this kind of association.

7.3. Unidirectional associations with join tables


7.3.1. one to many

A unidirectional one-to-many association on a join table is much preferred. Notice that


 by specifying unique="true", we have changed
ch anged the multiplicity from many-to-many to
one-to-many.

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

7.3.2. many to one


A unidirectional many-to-one association on a join table is quite common when the
association is optional.

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

7.3.3. one to one

A unidirectional one-to-one association on a join table is extremely unusual, but


 possible.

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

7.3.4. many to many

Finally, h ave a unidirectional many-to-many association.


Finally, we have association.

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

7.4. Bidirectional associations


7.4.1. one to many / many to one

A bidirectional many-to-one association is the most common kind of association. (This is


the standard parent/child relationship.)

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

If you use a List (or other indexed collection) you need to set the key column of the
foreign key to not null, and let Hibernate manage the association from the collections
side to maintain the index of
o f each element (making the other side virtually inverse by
setting update="false" and 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>

It is important that you define not-null="true" on the <key> element of the collection
mapping if the underlying foreign key
ke y column is NOT NULL. Don't only declare not-
null="true" on a possible nested <column> element, but on the <key> element.

7.4.2. one to one

A bidirectional one-to-one association on a foreign key is quite common.

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

A bidirectional one-to-one association on a primary key uses the special id generator.

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

7.5. Bidirectional associations with join tables


7.5.1. one to many / many to one

A bidirectional one-to-many association on a join table.


table. Note that the inverse="true"
can go on either end of the association, on the collection, or on the join.

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

7.5.2. one to one

A bidirectional one-to-one association on a join table is extremely unusual, but possible.

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

7.5.3. many to many

Finally, h ave a bidirectional many-to-many association.


Finally, we have association.

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

7.6. More complex association mappings


More complex association joins are extremely rare. Hibernate makes it possible to handle
more complex situations using SQL fragments embedded in the mapping document. For 
example, if a table with historical
h istorical account information data defines accountNumber,
effectiveEndDate and effectiveStartDatecolumns, mapped as follows:

<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"/>
Then we can map an association to the current instance
current instance (the one with null
effectiveEndDate) using:

<many-to-one name="currentAccountInfo"
property-ref="currentAccountKey"
class="AccountInfo">
<column name="accountNumber"/>
<formula>'1'</formula>
</many-to-one>

In a more complex example, imagine that the association between Employee and
Organization is maintained in an Employment table full of historical employment data.
Then an association to the employee's most recent employer
recent employer (the one with the most recent
startDate) might be mapped this way:
wa y:

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

You can get


ge t quite creative with this functionality,
functionality, but it is usually more practical to handle
these kinds of cases using HQL or a criteria query.
query.

Hibernate: Understanding Associations - Associations:


What are They?

(Page 3 of 4 )

To represent relationships between classes, associations are used. Before going into the
details of how Hibernate perceives associations, an understanding of the working of 
container managed associations is needed. Managed association means that, if a change is
made to one end of the association, it will be reflected at the other end.

For example, let's consider the Order table. If it has a one-to-many relationship with the
Product table, the Order class will have a one-to-many association with the Product class.
So when changes are made to the attributes participating in this association, they will be
reflected at the other end automatically. The developer doesn’t have to mange the
associations manually.
manually.
How Hibernate implements the management of association is different from that of 
Container Managed Relationships/Associations or CMR generally provided b y EJB CMP. CMP.
In CMR the association is bidirectional, whereas Hibernate treats each association as
different. The primary reason is that Hibernate builds its persistence based on Plain Old
Java Object or POJO, and in Java associations are unidirectional. Thus Hibernate doesn’t
implement CMR. So the associations are unidirectional. In essence it means if the on-
update-cascade attribute is set in the mapping for Order and not in Product, any
an y operation
on Product would not affect Order.

Keeping these points in mind, let's move on to the different types of associations
supported by Hibernate. Hibernate mainly supports two types of associations:

1. One-to-Many
2. Many-to-One

To work with associations, the changes would


wou ld be required in both the mapping as well as
in the persistence class. The details are as follows:

1. One-to-Many:

In this kind of association


association one object of a class is
is in a relationship with many objects of 
another class. The class that is having the single instance contains a collection of 
instances of the other class. To specify this association the mapping file would have to be
modified. The added code would be:

<one-to-many
name=” nameOfheVariable
column=" NAME_OF_THE_COLUMN "
class="ClassName"
not-null="true"/>

The name attribute takes the name of the variable that is participating in the association.
The column attribute is used to specify the table column that is participating in the
association. The class attribute takes the class name to which this class is associated. In
the Persistent class the following change would be there:

class <className>
{
//other variable declarations
Set <className> =new HashSet();
//constructors and getter/setter code follows
:
}
Then the constructor with the added
ad ded parameter for Set must be given along
a long with the getter 
and setter for the Set. In the third section I will be discussing a real world example to
illustrate this point.

2. Many-to-One:

This is the opposite of the One-to-Many association. In this case, the class that is having a
Many-to-One association contains the object of the class. For example, if class A has a
Many-to-One association with class B, then each instance of B would have an instance of 
A. And the identity of this instance can be the same for multiple objects of B. The change
in the mapping would be:

<many-to-one
name=” nameOfheVariable
column=" NAME_OF_THE_COLUMN "
class="ClassName"
not-null="true"/>

The attributes are the same as the case of One-to-Many.


One-to-Many. In the case of code it would be

class <className>
{
<classNameofAssociatedClass> o=new
<classNameofAssociatedClass>
//construtors and getter/setter code follows
:
}

The associations will be clearer when I discuss the real world usage of association in the
next section.

Hibernate: Understanding Associations - Associations in


the Real World

(Page 4 of 4 )

Till now I was using only one table. Let's make things interesting by adding one more
table. This table is the Product table. Each Order can have more than one Product. Hence
the relationship between Order and Product is One-to-Many. The schema of the Product
table is:
CREATE TABLE PRODUCT(
ID VARCHAR NOT NULL PRIMARY KEY,
NAME VARCHAR NOT NULL,
PRICE DOUBLE NOT NULL,
AMOUNT INTEGER NOT NULL,
ORDER_ID VARCHAR NOT NULL)

The next step is to create the persistent class for the Product table. The persistent class is
as follows:

package com.someorg.persist;

public class Product {


private String id;
private String name;
private double price;
private int amount;
private Order order;

public Product(String id, String name, double price, int


amount, Order
order)
{
this.order=order;
//others not shown for brevity
}
public String getId() {
return id;
}
public void setId(String string) {
id = string;
}
// default constructor and other
// getters/setters not shown for brevity
// ...
}

The next part is Product.hbm.xml, that is the mapping file:

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-
2.0.dtd">

<hibernate-mapping>
<class name="test.hibernate.Product"
table="products">

<id name="id" type="string"


unsaved-value="null">
<column name="id" sql-type="char(32)"
not-null="true"/>
<generator class="assigned"/>
</id>
<property name="name">
<column name="name" sql-type="char(255)"
not-null="true"/>
</property>
<property name="price">
<column name="price" sql-type="double"
not-null="true"/>
</property>
<property name="amount">
<column name="amount" sql-type="integer"
not-null="true"/>
</property>
<property name="orderId">
<column name="ORDER_ID" sql-type="char(255)"
not-null="true"/>

<many-to-one
name="orderId"
column="ORDER_ID"
class="ORDER"
not-null="true"/>

</class>
</hibernate-mapping>

That is all that is required for the Product table. Now we need to make some changes in
the Order class.

package com.someorg.persist;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class Order {
private String id;
private Date date;
private double priceTotal;
private Set products =new HashSet();
// Automatically set the creation time of
// this Order
public Order() {
this.date = new Date();
}

public Order(String id, Date date, private double


priceTotal, Set products){
this.products=products;
//others are not shown for brevity
}
public String getId() {
return id;
}

public void setProducts(Set products) {


this.products = products;
}

public Set getProducts () {


return products;
}

public void setId(String string) {


id = string;
}
// other getters/setters not shown for
// brevity
// ...
}

The next part is changing in the Order.hbm.xml, which is:

<?xml version='1.0' encoding='utf-8'?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-
3.0.dtd">
<hibernate-mapping default-cascade="none" default-
access="property" auto-import="true">
<class name=" com.someorg.persist.Order" table="orders"
mutable="true" select- before-update="false" optimistic-
lock="version">
<id name="id" type="string" unsaved-value="null">
<column name="id" sql-type="char(32)" not-null="true" />
<generator class="assigned" />
</id>
<property name="date" not-null="false" >
<column name="order_date" sql-type="datetime" not-
null="true" />
</property>
<property name="priceTotal" not-null="false" >
<column name="price_total" sql-type="double" not-
null="true" />
</property>

<set name="products">
<key column="PRODUCT_ID"/>
<one-to-many class="Product"/>
</set>

</class>
</hibernate-mapping>

The next step is to test it. To test it I will be using the Criteria query. In a QBC the joins
are done using the setFetchMode method of the Criteria class. The mode would be JOIN.
Here is how it works:

import java.util.List;
//other imports
// use as
// java test. FindOrderById name
public class FindOrderById {
public static void main(String[] args) throws Exception
{
// query to issue
String query =
"select order from Order "
+ "where order.id=:id";
// search for what?
String name = args[0];
// init
Configuration cfg = new Configuration()
.addClass(Order.class);
SessionFactory sf = cfg.buildSessionFactory();
// open session
Session sess = sf.openSession();

// search and return


Criteria criteria =
session.createCriteria(Order.class);
criteria.add( Expression.eq("id", name) )

.setFetchMode(“products”,FetchMode.JOIN);
List result = criteria.list();

if (list.size() == 0) {
System.out.println("No Order having id "
+ name);
System.exit(0);
}
Order o = (Order) list.get(0);
sess.close();
System.out.println("Found Order: " + o);//this is
just an example Here the o //
//object can be traversed to achieve anything
}
}

That brings us to the end of this discussion. Though the complete picture is becoming
clear, some edges are still hazy.
hazy. These edges will be brought
brough t into sharper focus in the
forthcoming discussions. Till next time.

You might also like