• No results found

Hibernate Associations

N/A
N/A
Protected

Academic year: 2021

Share "Hibernate Associations"

Copied!
18
0
0

Loading.... (view fulltext now)

Full text

(1)

Chapter 7. Association Mappings

Chapter 7. Association Mappings

Prev

Prev

 Next

 Next

Chapter 7. Association Mappings

Chapter 7. Association Mappings

7.1. Introduction

7.1. Introduction

Association mappings are the often most difficult thing to get right. In

Association mappings are the often most difficult thing to get right. In this section we'll

this section we'll

go through the canonical cases one by one, starting with unidirectional mappings, and

go through the canonical cases one by one, starting with unidirectional mappings, and

then considering the

then considering the bidirectional cases. W

bidirectional cases. We'll use

e'll use

PersonPerson

and

and

AddressAddress

in all the

in all the

examples.

examples.

W

We'll classify associations by whether or not they map to an

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

intervening join table, and by

multiplicity.

multiplicity.

 Nullable foreign keys are not considered

 Nullable foreign keys are not considered good practice in traditional data modelling, so

good practice in traditional data modelling, so

all our examples use not

all our examples use not null foreign keys. This is not a requirement of Hibernate, and

null foreign keys. This is not a requirement of Hibernate, and the

the

mappings will all work if you drop the nullability constraints.

mappings will all work if you drop the nullability constraints.

7.2. Unidirectional associations

7.2. Unidirectional associations

7.2.1. many to one

7.2.1. many to one

A

A unidirectional many-to-one association

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

is the most common kind of unidirectional

association.

association.

<class name="Person"> <class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" not-null="true"/> not-null="true"/> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key, addressId create table Person ( personId bigint not null primary key, addressId bigint not null )

bigint not null )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.2.2. one to one

7.2.2. one to one

(2)

A

A unidirectional one-to-one association on a foreign key

unidirectional one-to-one association on a foreign key is almost identical. The only

is almost identical. The only

difference is the column unique constraint.

difference is the column unique constraint.

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" unique="true" unique="true" not-null="true"/> not-null="true"/> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key, addressId create table Person ( personId bigint not null primary key, addressId bigint not null unique )

bigint not null unique )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

A

A unidirectional one-to-one association on a primary key

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

usually uses a special id

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

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

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> </class> </class> <class name="Address"> <class name="Address">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="foreign"> <generator class="foreign"> <param name="property">person</param> <param name="property">person</param> </generator> </generator> </id> </id>

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

</class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )

7.2.3. one to many

7.2.3. one to many

A

A unidirectional one-to-many association on a

unidirectional one-to-many association on a foreign key

foreign key is a very unusual case, and

is a very unusual case, and is

is

not really recommended.

not really recommended.

<class name="Person"> <class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <set name="addresses"> <set name="addresses">

(3)

<key column="personId" <key column="personId" not-null="true"/> not-null="true"/> <one-to-many class="Address"/> <one-to-many class="Address"/> </set> </set> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table Address ( addressId bigint not null primary key, personId create table Address ( addressId bigint not null primary key, personId bigint not null )

bigint not null )

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

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

7.3. Unidirectional associations with join tables

7.3. Unidirectional associations with join tables

7.3.1. one to many

7.3.1. one to many

A

A unidirectional one-to-many association on a join table

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

is much preferred. Notice that

 by specifying

 by specifying

unique="true"unique="true"

, we have ch

, we have changed the multiplicity from many-to-many to

anged the multiplicity from many-to-many to

one-to-many.

one-to-many.

<class name="Person"> <class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id>

</id>

<set name="addresses" table="PersonAddress"> <set name="addresses" table="PersonAddress">

<key column="personId"/> <key column="personId"/> <many-to-many column="addressId" <many-to-many column="addressId" unique="true" unique="true" class="Address"/> class="Address"/> </set> </set> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table PersonAddress ( personId not null, addressId bigint not create table PersonAddress ( personId not null, addressId bigint not null primary key )

null primary key )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.3.2. many to one

7.3.2. many to one

(4)

A

A unidirectional many-to-one association on a join table

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

is quite common when the

association is optional.

association is optional.

<class name="Person"> <class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <join table="PersonAddress" <join table="PersonAddress" optional="true"> optional="true">

<key column="personId" unique="true"/> <key column="personId" unique="true"/> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" not-null="true"/> not-null="true"/> </join> </join> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table PersonAddress ( personId bigint not null primary key, create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )

addressId bigint not null )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.3.3. one to one

7.3.3. one to one

A

A unidirectional one-to-one association on a join table

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

is extremely unusual, but

 possible.

 possible.

<class name="Person"> <class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <join table="PersonAddress" <join table="PersonAddress" optional="true"> optional="true"> <key column="personId" <key column="personId" unique="true"/> unique="true"/> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" not-null="true" not-null="true" unique="true"/> unique="true"/> </join> </join> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

(5)

create table PersonAddress ( personId bigint not null primary key, create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )

addressId bigint not null unique )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.3.4. many to many

7.3.4. many to many

Finally

Finally, we h

, we have a

ave a unidirectional many-to-many association

unidirectional many-to-many association..

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id>

</id>

<set name="addresses" table="PersonAddress"> <set name="addresses" table="PersonAddress">

<key column="personId"/> <key column="personId"/> <many-to-many column="addressId" <many-to-many column="addressId" class="Address"/> class="Address"/> </set> </set> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table PersonAddress ( personId bigint not null, addressId bigint create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )

not null, primary key (personId, addressId) )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.4. Bidirectional associations

7.4. Bidirectional associations

7.4.1. one to many / many to one

7.4.1. one to many / many to one

A

A bidirectional many-to-one association

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

is the most common kind of association. (This is

the standard parent/child relationship.)

the standard parent/child relationship.)

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" not-null="true"/> not-null="true"/> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id>

</id>

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

<key column="addressId"/> <key column="addressId"/>

(6)

<one-to-many class="Person"/> <one-to-many class="Person"/> </set> </set> </class> </class>

create table Person ( personId bigint not null primary key, addressId create table Person ( personId bigint not null primary key, addressId bigint not null )

bigint not null )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

If you use a

If you use a

ListList

(or other indexed collection) you need to set the

(or other indexed collection) you need to set the

keykey

column of the

column of the

foreign key to

foreign key to

not nullnot null

, and let Hibernate manage the association from the collections

, and let Hibernate manage the association from the collections

side to maintain the index o

side to maintain the index of each element (making the other

f each element (making the other side virtually inverse by

side virtually inverse by

setting

setting

update="false"update="false"

and

and

insert="false"insert="false"

):

):

<class name="Person"> <class name="Person"> <id name="id"/> <id name="id"/> ... ... <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" not-null="true" not-null="true" insert="false" insert="false" update="false"/> update="false"/> </class> </class> <class name="Address"> <class name="Address"> <id name="id"/> <id name="id"/> ... ... <list name="people"> <list name="people">

<key column="addressId" not-null="true"/> <key column="addressId" not-null="true"/> <list-index column="peopleIdx"/> <list-index column="peopleIdx"/> <one-to-many class="Person"/> <one-to-many class="Person"/> </list> </list> </class> </class>

It is important that you define

It is important that you define

not-null="true"not-null="true"

on the

on the

<key><key>

element of the collection

element of the collection

mapping if the underlying foreign ke

mapping if the underlying foreign key column is

y column is

NOT NULLNOT NULL

. Don't only declare

. Don't only declare

not- not-null="true"

null="true"

on a possible nested

on a possible nested

<column><column>

element, but on the

element, but on the

<key><key>

element.

element.

7.4.2. one to one

7.4.2. one to one

A

A bidirectional one-to-one association on a foreign key

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

is quite common.

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" unique="true" unique="true" not-null="true"/> not-null="true"/> </class> </class> <class name="Address"> <class name="Address">

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

(7)

<generator class="native"/> <generator class="native"/> </id> </id> <one-to-one name="person" <one-to-one name="person" property-ref="address"/> property-ref="address"/> </class> </class>

create table Person ( personId bigint not null primary key, addressId create table Person ( personId bigint not null primary key, addressId bigint not null unique )

bigint not null unique )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

A

A bidirectional one-to-one association on a primary key

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

uses the special id generator.

generator.

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <one-to-one name="address"/> <one-to-one name="address"/> </class> </class> <class name="Address"> <class name="Address">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="foreign"> <generator class="foreign"> <param name="property">person</param> <param name="property">person</param> </generator> </generator> </id> </id> <one-to-one name="person" <one-to-one name="person" constrained="true"/> constrained="true"/> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )

7.5. Bidirectional associations with join tables

7.5. Bidirectional associations with join tables

7.5.1. one to many / many to one

7.5.1. one to many / many to one

A

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

bidirectional one-to-many association on a join table. Note that the

. Note that the

inverse="true"inverse="true"

can go on either end of the association, on the collection, or on the join.

can go on either end of the association, on the collection, or on the join.

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <set name="addresses" <set name="addresses" table="PersonAddress"> table="PersonAddress"> <key column="personId"/> <key column="personId"/> <many-to-many column="addressId" <many-to-many column="addressId" unique="true" unique="true" class="Address"/> class="Address"/> </set> </set> </class> </class> <class name="Address"> <class name="Address">

(8)

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

<generator class="native"/> <generator class="native"/> </id> </id> <join table="PersonAddress" <join table="PersonAddress" inverse="true" inverse="true" optional="true"> optional="true"> <key column="addressId"/> <key column="addressId"/> <many-to-one name="person" <many-to-one name="person" column="personId" column="personId" not-null="true"/> not-null="true"/> </join> </join> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table PersonAddress ( personId bigint not null, addressId bigint create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )

not null primary key )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.5.2. one to one

7.5.2. one to one

A

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

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

is extremely unusual, but possible.

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id> </id> <join table="PersonAddress" <join table="PersonAddress" optional="true"> optional="true"> <key column="personId" <key column="personId" unique="true"/> unique="true"/> <many-to-one name="address" <many-to-one name="address" column="addressId" column="addressId" not-null="true" not-null="true" unique="true"/> unique="true"/> </join> </join> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id> </id> <join table="PersonAddress" <join table="PersonAddress" optional="true" optional="true" inverse="true"> inverse="true"> <key column="addressId" <key column="addressId" unique="true"/> unique="true"/> <many-to-one name="person" <many-to-one name="person" column="personId" column="personId" not-null="true" not-null="true" unique="true"/> unique="true"/> </join> </join> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table PersonAddress ( personId bigint not null primary key, create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )

(9)

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.5.3. many to many

7.5.3. many to many

Finally

Finally, we h

, we have a

ave a bidirectional many-to-many association

bidirectional many-to-many association..

<class name="Person">

<class name="Person">

<id name="id" column="personId"> <id name="id" column="personId"> <generator class="native"/> <generator class="native"/> </id>

</id>

<set name="addresses" table="PersonAddress"> <set name="addresses" table="PersonAddress">

<key column="personId"/> <key column="personId"/> <many-to-many column="addressId" <many-to-many column="addressId" class="Address"/> class="Address"/> </set> </set> </class> </class> <class name="Address"> <class name="Address">

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

<generator class="native"/> <generator class="native"/> </id>

</id>

<set name="people" inverse="true" table="PersonAddress"> <set name="people" inverse="true" table="PersonAddress">

<key column="addressId"/> <key column="addressId"/> <many-to-many column="personId" <many-to-many column="personId" class="Person"/> class="Person"/> </set> </set> </class> </class>

create table Person ( personId bigint not null primary key ) create table Person ( personId bigint not null primary key )

create table PersonAddress ( personId bigint not null, addressId bigint create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )

not null, primary key (personId, addressId) )

create table Address ( addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.6. More complex association mappings

7.6. More complex association mappings

More complex association joins are

More complex association joins are extremely

extremely rare. Hibernate makes it possible to handle

rare. Hibernate makes it possible to handle

more complex situations using SQL fragments embedded in the mapping

more complex situations using SQL fragments embedded in the mapping document. For 

document. For 

example, if a table with h

example, if a table with historical account information data defines

istorical account information data defines

accountNumberaccountNumber

,,

effectiveEndDate

effectiveEndDate

and

and

effectiveStartDateeffectiveStartDate

columns, mapped as follows:

columns, mapped as follows:

<properties name="currentAccountKey">

<properties name="currentAccountKey">

<property name="accountNumber" type="string" not-null="true"/> <property name="accountNumber" type="string" not-null="true"/> <property name="currentAccount" type="boolean">

<property name="currentAccount" type="boolean">

<formula>case when effectiveEndDate is null then 1 else 0 <formula>case when effectiveEndDate is null then 1 else 0 end</formula> end</formula> </property> </property> </properties> </properties>

<property name="effectiveEndDate" type="date"/> <property name="effectiveEndDate" type="date"/>

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

(10)

Then we can map an association to the

Then we can map an association to the current 

current instance (the one with null

instance (the one with null

effectiveEndDate

effectiveEndDate

) using:

) using:

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

In a more complex example, imagine that the association between

In a more complex example, imagine that the association between

EmployeeEmployee

and

and

Organization

Organization

is maintained in an

is maintained in an

EmploymentEmployment

table full of historical employment data.

table full of historical employment data.

Then an association to the employee's

Then an association to the employee's most recent 

most recent employer (the one with the most recent

employer (the one with the most recent

startDate

startDate

) might be mapped this wa

) might be mapped this way:

y:

<join> <join> <key column="employeeId"/> <key column="employeeId"/> <subselect> <subselect>

select employeeId, orgId select employeeId, orgId from Employments

from Employments group by orgId group by orgId

having startDate = max(startDate) having startDate = max(startDate) </subselect> </subselect> <many-to-one name="mostRecentEmployer" <many-to-one name="mostRecentEmployer" class="Organization" class="Organization" column="orgId"/> column="orgId"/> </join> </join>

Y

You can ge

ou can get quite creative with

t quite creative with this functionality

this functionality, but it

, but it is usually more practical to

is usually more practical to handle

handle

these kinds of

these kinds of cases using HQL or a

cases using HQL or a criteria query

criteria query..

Hibernate: Understanding Associations - Associations:

Hibernate: Understanding Associations - Associations:

What are They?

What are They?

(Page 3 of 4 )

(Page 3 of 4 )

T

To represent relationships between classes, associations are used. Before going

o represent relationships between classes, associations are used. Before going into the

into the

details of how Hibernate perceives associations, an understanding of the working of 

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

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.

made to one end of the association, it will be reflected at the other end.

For example, let's consider the Order table.

For example, let's consider the Order table. If it has a one-to-many relationship with the

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.

Product table, the Order class will have a one-to-many association with the Product class.

So when changes are

So when changes are made to the attributes participating in this association, they will be

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

reflected at the other end automatically. The developer doesn’t have to mange the

associations

(11)

How Hibernate implements the management of association is different from that of 

How Hibernate implements the management of association is different from that of 

Container Managed

Container Managed Relationships/Associations or CMR generally provided b

Relationships/Associations or CMR generally provided b y EJB CMP

y EJB CMP..

In CMR the association is bidirectional, whereas Hibernate treats each

In CMR the association is bidirectional, whereas Hibernate treats each association as

association as

different. The primary reason is that Hibernate builds its persistence based on Plain Old

different. The primary reason is that Hibernate builds its persistence based on Plain Old

Java Object or POJO, and in

Java Object or POJO, and in Java associations are unidirectional. Thus Hibernate doesn’t

Java associations are unidirectional. Thus Hibernate doesn’t

implement CMR. So the associations are unidirectional. In essence it means if the

implement CMR. So the associations are unidirectional. In essence it means if the

on-update-cascade attribute is set in the mapping

update-cascade attribute is set in the mapping for Order and not in Product, an

for Order and not in Product, any operation

y operation

on Product would

on Product would not affect Order.

not affect Order.

Keeping these points in mind,

Keeping these points in mind, let's move on to the different types of associations

let's move on to the different types of associations

supported by Hibernate. Hibernate mainly supports two types of associations:

supported by Hibernate. Hibernate mainly supports two types of associations:

1. One-to-Many

1. One-to-Many

2. Many-to-One

2. Many-to-One

T

To work with associations, the changes wou

o work with associations, the changes would be required in both the

ld be required in both the mapping as well as

mapping as well as

in the persistence class. The details are as follows:

in the persistence class. The details are as follows:

1. One-to-Many:

1. One-to-Many:

In this kind of associ

In this kind of association one object of a class i

ation one object of a class is in a relationship

s in a relationship with many

with many objects of 

objects of 

another class. The class that is having the single instance contains a collection 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

instances of the other class. To specify this association the mapping file would have to be

modified. The added code would be:

modified. The added code would be:

<one-to-many

<one-to-many

name=”

name=”

 nameOfheVariable nameOfheVariable

column="

column="

 NAME_OF_THE_COLUMN  NAME_OF_THE_COLUMN 

"

"

class="ClassName"

class="ClassName"

not-null="true"/>

not-null="true"/>

The name attribute takes the

The name attribute takes the name of the variable that is participating in

name of the variable that is participating in the association.

the association.

The column attribute is used to

The column attribute is used to specify the table column that is participating in the

specify the table column that is participating in the

association. The class attribute takes the class name to which

association. The class attribute takes the class name to which this class is associated. In

this class is associated. In

the Persistent class the following change would be

the Persistent class the following change would be there:

there:

class <className>

class <className>

{

{

//other variable declarations

//other variable declarations

Set <className> =new HashSet();

Set <className> =new HashSet();

//constructors and getter/setter code follows

//constructors and getter/setter code follows

:

:

}

(12)

Then the constructor with the ad

Then the constructor with the added parameter for Set must be given a

ded parameter for Set must be given along with the getter 

long with the getter 

and setter for the Set. In the

and setter for the Set. In the third section I will be discussing a real world example

third section I will be discussing a real world example to

to

illustrate this point.

illustrate this point.

2. Many-to-One:

2. Many-to-One:

This is the opposite of the One-to-Many association. In this case, the class that is having a

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

Many-to-One association contains the object of the

object of the class. For example, if

class. For example, if class A

class A has a

has a

Many-to-One association with class B, then each instance

Many-to-One association with class B, then each instance of B would have an

of B would have an instance of 

instance of 

A. And the identity of this instance can be the same for multiple

A. And the identity of this instance can be the same for multiple objects of B. The change

objects of B. The change

in the mapping would be:

in the mapping would be:

<many-to-one

<many-to-one

name=”

name=”

 nameOfheVariable nameOfheVariable

column="

column="

 NAME_OF_THE_COLUMN  NAME_OF_THE_COLUMN 

"

"

class="ClassName"

class="ClassName"

not-null="true"/>

not-null="true"/>

The attributes are the same as the

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

case of One-to-Many. In the case of

. In the case of code it would be

code it would be

class <className>

class <className>

{

{

<classNameofAssociatedClass> o=new

<classNameofAssociatedClass> o=new

<classNameofAssociatedClass>

<classNameofAssociatedClass>

//construtors and getter/setter code follows

//construtors and getter/setter code follows

:

:

}

}

The associations will be clearer when I

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

discuss the real world usage of association in the

next section.

next section.

Hibernate: Understanding Associations - Associations in

Hibernate: Understanding Associations - Associations in

the Real World

the Real World

(Page 4 of 4 )

(Page 4 of 4 )

Till now I was using only one table. Let's make

Till now I was using only one table. Let's make things interesting by adding one more

things interesting by adding one more

table. This table is the Product table. Each Order can have more than one Product. Hence

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

the relationship between Order and Product is One-to-Many. The schema of the Product

table is:

(13)

CREATE TABLE PRODUCT(

CREATE TABLE PRODUCT(

ID VARCHAR NOT NULL PRIMARY KEY,

ID VARCHAR NOT NULL PRIMARY KEY,

NAME VARCHAR NOT NULL,

NAME VARCHAR NOT NULL,

PRICE DOUBLE NOT NULL,

PRICE DOUBLE NOT NULL,

AMOUNT INTEGER NOT NULL,

AMOUNT INTEGER NOT NULL,

ORDER_ID VARCHAR NOT NULL)

ORDER_ID VARCHAR NOT NULL)

The next step is to create

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

the persistent class for the Product table. The persistent class is

as follows:

as follows:

package com.someorg.persist;

package com.someorg.persist;

public class Product {

public class Product {

private String id;

private String id;

private String name;

private String name;

private double price;

private double price;

private int amount;

private int amount;

private Order order;

private Order order;

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

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

amount, Order

amount, Order

order)

order)

{

{

this.order=order;

this.order=order;

//others not shown for brevity

//others not shown for brevity

}

}

public String getId() {

public String getId() {

return id;

return id;

}

}

public void setId(String string) {

public void setId(String string) {

id = string;

id = string;

}

}

// default constructor and other

// default constructor and other

// getters/setters not shown for brevity

// getters/setters not shown for brevity

// ...

// ...

}

}

The next part is Product.hbm.xml, that is the

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

mapping file:

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

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

(14)

<!DOCTYPE hibernate-mapping

<!DOCTYPE hibernate-mapping

PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

2.0.dtd">

<hibernate-mapping>

<hibernate-mapping>

<class name="test.hibernate.Product"

<class name="test.hibernate.Product"

table="products">

table="products">

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

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

unsaved-value="null">

unsaved-value="null">

<column name="id" sql-type="char(32)"

<column name="id" sql-type="char(32)"

not-null="true"/>

not-null="true"/>

<generator class="assigned"/>

<generator class="assigned"/>

</id>

</id>

<property name="name">

<property name="name">

<column name="name" sql-type="char(255)"

<column name="name" sql-type="char(255)"

not-null="true"/>

not-null="true"/>

</property>

</property>

<property name="price">

<property name="price">

<column name="price" sql-type="double"

<column name="price" sql-type="double"

not-null="true"/>

not-null="true"/>

</property>

</property>

<property name="amount">

<property name="amount">

<column name="amount" sql-type="integer"

<column name="amount" sql-type="integer"

not-null="true"/>

not-null="true"/>

</property>

</property>

<property name="orderId">

<property name="orderId">

<column name="ORDER_ID" sql-type="char(255)"

<column name="ORDER_ID" sql-type="char(255)"

not-null="true"/>

not-null="true"/>

<many-to-one

<many-to-one

name="orderId"

name="orderId"

column="ORDER_ID"

column="ORDER_ID"

class="ORDER"

class="ORDER"

not-null="true"/>

not-null="true"/>

</class>

</class>

(15)

</hibernate-mapping>

</hibernate-mapping>

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

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

the Order class.

the Order class.

package com.someorg.persist;

package com.someorg.persist;

import java.util.Date;

import java.util.Date;

import java.util.HashSet;

import java.util.HashSet;

import java.util.Set;

import java.util.Set;

public class Order {

public class Order {

private String id;

private String id;

private Date date;

private Date date;

private double priceTotal;

private double priceTotal;

private Set products =new HashSet();

private Set products =new HashSet();

// Automatically set the creation time of

// Automatically set the creation time of

// this Order

// this Order

public Order() {

public Order() {

this.date = new Date();

this.date = new Date();

}

}

public Order(String id, Date date, private double

public Order(String id, Date date, private double

priceTotal,

priceTotal,

Set products

Set products){

){

this.products=products;

this.products=products;

//others are not shown for brevity

//others are not shown for brevity

}

}

public String getId() {

public String getId() {

return id;

return id;

}

}

public void setProducts(Set products) {

public void setProducts(Set products) {

this.products = products;

this.products = products;

}

}

public Set getProducts () {

public Set getProducts () {

return products;

return products;

}

}

public void setId(String string) {

public void setId(String string) {

id = string;

id = string;

}

}

// other getters/setters not shown for

// other getters/setters not shown for

(16)

// brevity

// brevity

// ...

// ...

}

}

The next part is changing

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

in the Order.hbm.xml, which is:

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

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

<!DOCTYPE hibernate-configuration PUBLIC

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

3.0.dtd">

<hibernate-mapping cascade="none"

<hibernate-mapping cascade="none"

default-access="property" auto-import="true">

access="property" auto-import="true">

<class name=" com.someorg.persist.Order" table="orders"

<class name=" com.someorg.persist.Order" table="orders"

mutable="true" select- before-update="false"

mutable="true" select- before-update="false"

optimistic-lock="version">

lock="version">

<id name="id" type="string" unsaved-value="null">

<id name="id" type="string" unsaved-value="null">

<column name="id" sql-type="char(32)" not-null="true" />

<column name="id" sql-type="char(32)" not-null="true" />

<generator class="assigned" />

<generator class="assigned" />

</id>

</id>

<property name="date" not-null="false" >

<property name="date" not-null="false" >

<column name="order_date" sql-type="datetime"

<column name="order_date" sql-type="datetime"

not-null="true" />

null="true" />

</property>

</property>

<property name="priceTotal" not-null="false" >

<property name="priceTotal" not-null="false" >

<column name="price_total" sql-type="double"

<column name="price_total" sql-type="double"

not-null="true" />

null="true" />

</property>

</property>

<set name="products">

<set name="products">

<key column="PRODUCT_ID"/>

<key column="PRODUCT_ID"/>

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

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

</set>

</set>

</class>

</class>

</hibernate-mapping>

</hibernate-mapping>

The next step is to test it. To test it I will be using the Criteria query. In a QBC the joins

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

are done using the setFetchMode method of the Criteria class. The mode would be

setFetchMode method of the Criteria class. The mode would be JOIN.

JOIN.

Here is how it works:

Here is how it works:

import java.util.List;

import java.util.List;

(17)

//other imports

//other imports

// use as

// use as

// java test. FindOrderById name

// java test. FindOrderById name

public class FindOrderById {

public class FindOrderById {

public static void main(String[] args) throws Exception

public static void main(String[] args) throws Exception

{

{

// query to issue

// query to issue

String query =

String query =

"select order from Order "

"select order from Order "

+ "where order.id=:id";

+ "where order.id=:id";

// search for what?

// search for what?

String name = args[0];

String name = args[0];

// init

// init

Configuration cfg = new Configuration()

Configuration cfg = new Configuration()

.addClass(Order.class);

.addClass(Order.class);

SessionFactory sf = cfg.buildSessionFactory();

SessionFactory sf = cfg.buildSessionFactory();

// open session

// open session

Session sess = sf.openSession();

Session sess = sf.openSession();

// search and return

// search and return

Criteria criteria =

Criteria criteria =

session.createCriteria(Order.class);

session.createCriteria(Order.class);

criteria.add( Expression.eq("id", name) )

criteria.add( Expression.eq("id", name) )

.setFetchMode(“products”,FetchMode.JOIN);

.setFetchMode(“products”,FetchMode.JOIN);

List result = criteria.list();

List result = criteria.list();

if (list.size() == 0) {

if (list.size() == 0) {

System.out.println("No Order having id "

System.out.println("No Order having id "

+ name);

+ name);

System.exit(0);

System.exit(0);

}

}

Order o = (Order) list.get(0);

Order o = (Order) list.get(0);

sess.close();

sess.close();

System.out.println("Found Order: " + o);//this is

System.out.println("Found Order: " + o);//this is

just an example Here the o //

just an example Here the o //

//object can be traversed to achieve anything

//object can be traversed to achieve anything

}

}

}

}

That brings us to the end

That brings us to the end of this discussion. Though the complete picture is becoming

of this discussion. Though the complete picture is becoming

clear, some edges are still hazy

clear, some edges are still hazy. These edges will be brough

. These edges will be brought into sharper focus in the

t into sharper focus in the

forthcoming discussions. Till next time.

(18)

References

Related documents