Tuesday, October 18, 2011

One to One association using Join Table

One-to-One association can also be done using a Join table between two entities. The join table will have two foreign key columns (i.e) it will have both the primary key columns from the two entity tables. One of the foreign keys will serve as the primary key for the join table. An unique constraint will be applied on the remaining foreign key column and hence both the foreign key columns will not have the duplicate values. This is how the goal of one-to-one is achieved using the join table between two entities. The example will explain this more in detail.

Mapping using Hibernate XML mapping:

Let us go to the package com.demo.oneToOneUsingJoinTable and execute the java class OneToOneUsingJoinTableExecutor.java.

Things to look into:

* The ORM classes Person.java and Passport.java
* The xml mapping file oneToOneUsingJoinTable.hbm.xml

ORM:

public class Person {

private long id;

private String name;

private Passport passport;

// getter and setter methods
}

public class Passport {

private long id;

private String passportNumber;

private Person person;

// getter and setter methods
}

XML:

<hibernate-mapping>
<class name="com.demo.oneToOneUsingJoinTable.Person" table="PERSON"
lazy="false">
<id name="id" column="PERSON_ID">
<generator class="native" />
</id>
<property name="name" column="NAME" />
<join table="PASSPORTS" optional="true">
<key column="PERSON_ID" />
<many-to-one name="passport" column="PASSPORT_ID"
not-null="true" unique="true" cascade="save-update"/>
</join>
</class>

<class name="com.demo.oneToOneUsingJoinTable.Passport" table="PASSPORT" lazy="false">
<id name="id" column="PASSPORT_ID">
<generator class="native" />
</id>
<property name="passportNumber" column="PASSPORT_NUMBER" />
<join table="PASSPORTS" optional="true" inverse="true">
<key column="PASSPORT_ID" unique="true"/>
<many-to-one name="person" column="PERSON_ID" not-null="true"
unique="true" />
</join>
</class>
</hibernate-mapping>

* <joing> represents the join table that will be used, here in this case it is "PASSPORTS"
* key represents the foreign key column of the join table.
* optional="true" tells the hibernate that it should a row into the join table only if the properties grouped by this mapping are non-null.
* unique="true" represents the unique constraint on the column
* Note that the foreign key column PASSPORT_ID in the join table is made primary key by applying the unique="true"
* cascade specifies that the cascade side of the association will take of care of persisting the other side of the entity.
* inverse="true" declares that the entity on which it has been declared will not participate in updating the join table. Otherwise both entities will update the join table violating the constrains.
* In both the entities the many-to-one association is made to one-to-one association by applying the unique="true"

Once the OneToOneUsingJoinTableExecutor.java is executed, verify the results in the eclipse console as well as in the HSQL DB manager by executing simple select queries on the following tables PERSON, PASSPORT and the join table PASSPORTS as follows.



Mapping using Annotations:

Let us go to the package annotation.com.demo.oneToOneUsingJoingTable and execute the class OneToOneUsingJoinTableAnnotationExecutor.java

Things to look into:

The annotated ORM classes Person.java and Passport.java

@Entity(name="annotation.com.demo.oneToOneUsingJoingTable.Person")
@Table(name="PERSON")
public class Person {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="PERSON_ID")
private long id;

@Column(name="NAME")
private String name;

@OneToOne(cascade=CascadeType.ALL,mappedBy="person")
@JoinTable(name="PASSPORTS",joinColumns=@JoinColumn(name="PERSON_ID"),
inverseJoinColumns=@JoinColumn(name="PASSPORT_ID"))
private Passport passport;

//getter and setter methods
}


@Entity(name="annotation.com.demo.oneToOneUsingJoingTable.Passport")
@Table(name="PASSPORT")
public class Passport {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="PASSPORT_ID")
private long id;

@Column(name="PASSPORT_NUMBER")
private String passportNumber;

@OneToOne @JoinTable(name="PASSPORTS",joinColumns=@JoinColumn(name="PASSPORT_ID",unique=true),
inverseJoinColumns=@JoinColumn(name="PERSON_ID",unique=true))
private Person person;

//getter and setter methods
}

* @
JoinTable represents the join table that is used here.
* @JoinColumn refers the primary key of the source table as the foreign key column in the join table.
* inverseJoinColumns refers the primary key of the other side of the entity.
* @OneToOne refers the one-to-one association
* Here
mappedBy also plays the role of inverse="true" in the xml.

Once the class OneToOneUsingJoinTableAnnotationExecutor.java is executed, verify the results as mentioned above.