Tuesday, October 18, 2011

One to One association using Shared Primary key

Associations describe the associations between the entities. Hence in associations all the classes will have their own life cycle. One to One association can be done in three different ways.

1. Shared Primary Key association.
2. One-to-One foreign key association.
3. Using a join table.

Let us now look at the Shared Primary key way of one-to-one association.

Shared Primary key association:


The two tables which involve in this association share the same primary key value.


Mapping using Hibernate XML mapping:

Let us go to the package com.demo.oneToOneUsingPrimaryKey and execute the class OneToOnePKExecutor.java

Things to look into:


* The ORM classes User.java and Address.java
* The XML mapping file oneToOneUsingPrimaryKey.hbm.xml ORM:

public class User {

private long id;

private String name;

private Address address;

// getter and setter methods
}

public class Address {

private long id;
private String street;
private String zipCode;
private String city;

private User user;

// getter and setter methods
}

* Here the Address class is an entity and hence it has the id attribute. Also It has its own life cycle and reference.

XML:

<hibernate-mapping auto-import="false">
<class name="com.demo.oneToOneUsingPrimaryKey.User" table="USER" lazy="false">

<id name="id" column="USER_ID" type="long">
<generator class="native" /> </id> <property name="name" column="NAME" type="string" />
<
one-to-one name="address" class="com.demo.oneToOneUsingPrimaryKey.Address" cascade="save-update" />
</class>

<class name="com.demo.oneToOneUsingPrimaryKey.Address" table="ADDRESS">
<id name="id" column="ADDRESS_ID">
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<property name="street" column="STREET" />
<property name="zipCode" column="ZIPCODE" />
<property name="city" column="CITY" />

<one-to-one name="user" class="com.demo.oneToOneUsingPrimaryKey.User" constrained="true" />
</class>
</hibernate-mapping>



* The xml tag <one-to-one> is used to map the one-to-one association.
* casecade represents that any update or insert done on the User entity will automatically take care of its dependent entity classes. Here If User object is saved , then the Address object will be saved by the hibernate automatically.

* The primary generation in the Address table is bit different here because it shares the primary key of it's owing entity.

* constrained="true" makes the association bidirectional and adds foreign key constraint linking the primary key of the Address table to the primary key of the User table.

The conclusion is that both the User and the Address tables share the same primary key fulfilling the one-to-one association.

Once the OneToOnePKExecutor.java class is executed verify the results in the eclipse console and run the simple select queries on the tables User and Address as follows in the HSQL DB manager.




Mapping using Annotations:

Let us go to the package annotation.com.demo.oneToOneUsingPrimaryKey and execute class OneToOnePKAnnotationExecutor.java

Things to look into:

* The ORM classes User.java and Address.java

@Entity
@Table(name="USER")
public class User {

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

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

@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
@PrimaryKeyJoinColumn
private Address address;

// getter and setter methods
}

@Entity
@Table(name="ADDRESS")
public class Address {

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

@Column(name="STREET_NAME")
private String street;
@Column(name="ZIPCODE")
private String zipCode;
@Column(name="CITY_NAME")
private String city;

@OneToOne(fetch=FetchType.EAGER) //FetchType.EAGER sets the lazy loading to false
@PrimaryKeyJoinColumn
private User user;

// getter and setter methods
}

* The annotation @OneToOne specifies the one-to-one association
* The annotation @PrimaryKeyJoinColumn maps the shared primary key association.

Note: The JPA annotations directly does not support the shared primary key association. (i.e) to set the id of Address entity the same as the id of the User entity. Hence we need additional hibernate annotations which are not given in the example. Please have the following kind of annotation for id attribute if you really want to take care of this using hibernate annotations.

@Id
@GeneratedValue (generator = "myForeignGenerator")
@org.hibernate.annotations.GenericGenerator(
name="myForeignGenerator",
strategy="foreign",
parameters=@Parameter(name="property",value="user")
)
@Column(name="ADDRESS_ID")
private long id;

Once the OneToOnePKAnnotationExecutor.java is executed verify the results as mentioned above.