Sunday, March 20, 2011

Spring - Hibernate: Many-To-One Association - Explicitly Specify Join Table, Cascade, and Fetch

Introduction

In this tutorial we'll expand our previous project Spring - Hibernate: Many-To-One Association by explicitly specifying the join table and join columns. We will also declare the Cascade type and Fetch strategy for the @ManyToOne annotation.

Spring MVC 3 and Hibernate Tutorials Series
Spring - Hibernate: Many-To-One Association - Explicitly Specify Join Table, Cascade, and Fetch
Spring - Hibernate: One-To-Many Association - Explicitly Specify Join Table, Cascade, and Fetch
Spring - Hibernate: Many-To-One Association
Spring - Hibernate: One-To-Many Association
Spring MVC 3, Hibernate Annotations, MySQL Integration Tutorial
Spring MVC 3, Hibernate Annotations, HSQLDB Integration Tutorial

Changes

Using a diff tool, we can easily visualize the changes from the previous project and our updated project. Notice only CreditCard.java has changed. Everything else have remained the same.


Development

Similar with the original project, we'll split our development in three layers: Domain, Service, and Controller. But since only the domain has changed, we will only discuss the Domain layer. For the remaining layers, please see the original tutorial: Spring - Hibernate: Many-To-One Association

Domain Layer

For the domain layer, only CreditCard class has changed by adding extra properties to the @ManyToOne annotation.

CreditCard.java
package org.krams.tutorial.domain;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * Represents a credit card entity
 * 
 * @author Krams at {@link http://krams915@blogspot.com
 */
@Entity
@Table(name = "CREDIT_CARD")
public class CreditCard implements Serializable {

 private static final long serialVersionUID = 5924361831551833717L;

 @Id
 @Column(name = "ID")
 @GeneratedValue
 private Integer id;
 
 @Column(name = "TYPE")
 private String type;
 
 @Column(name = "NUMBER")
 private String number;

 @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER )
    @JoinTable(name="CREDIT_PERSON",
        joinColumns = @JoinColumn(name="CREDIT_ID"),
        inverseJoinColumns = @JoinColumn(name="PERSON_ID")
    )
 private Person person;
 
 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getType() {
  return type;
 }

 public void setType(String type) {
  this.type = type;
 }

 public String getNumber() {
  return number;
 }

 public void setNumber(String number) {
  this.number = number;
 }

 public Person getPerson() {
  return person;
 }

 public void setPerson(Person person) {
  this.person = person;
 }
 
 
}

Pay extra attention to the @ManyToOne annotation:

@Entity
@Table(name = "CREDIT_CARD")
public class CreditCard implements Serializable {
 ...
 @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch=FetchType.EAGER )
    @JoinTable(name="CREDIT_PERSON",
        joinColumns = @JoinColumn(name="CREDIT_ID"),
        inverseJoinColumns = @JoinColumn(name="PERSON_ID")
    )
 private Person person;
 ...
}

We have explicitly declared the join table name and the join column names.

Using phpymyadmin's database designer, the Hibernate auto-generated relationship between Person and CreditCard looks as follows


Again using phpymyadmin, the auto-generated tables looks as follows:

By specifying the @JoinTable, we forced Hibernate to create a third table that contains the relationship between Person and CreditCard. By default, @ManyToOne creates two tables.

Notice we have also specified the Cascade and Fetch strategies as well.

What does CascadeType.PERSIST and CascadeType.MERGE do?
CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if the entity is managed
CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed
CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called
CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called
CascadeType.DETACH: cascades the detach operation to associated entities if detach() is called

CascadeType.ALL: all of the above

Source: Hibernate Annotations Reference Guide

What does FetchType.EAGER do?
You have the ability to either eagerly or lazily fetch associated entities. The fetch parameter can be set to FetchType.LAZY or FetchType.EAGER. EAGER will try to use an outer join select to retrieve the associated object, while LAZY will only trigger a select when the associated object is accessed for the first time. @OneToMany and @ManyToMany associations are defaulted to LAZY and @OneToOne and @ManyToOne are defaulted to EAGER.

Source: Hibernate Annotations Reference Guide

Notice @ManyToOne are defaulted to EAGER. That means it's not necessary to declare the fetch=FetchType.EAGER inside the @ManyToOne. But we declared it anyway for the purpose of demonstrating its feature in this tutorial.

Configuration

We've completed the changes necessary for the project. The next step is to declare the configuration files. But since nothing has changed in the configuration files, we won't be posting them again here. Please see the original tutorial Spring - Hibernate: Many-To-One Association if you want to see the files.

Run the Application


Setup the database

Our application uses MySQL as its database. To run the application, make sure to setup the database first.

To create the database, follow these steps.
1. Open phpmyadmin (or any tool you prefer with)
2. Create a new database named mydatabase
3. Run the application to automatically create the database schema.

To populate the database with sample data, import the mydatabase.sql SQL script which is located under the WEB-INF folder of the application:


Access the main application

To access the main application, use the following URL:
http://localhost:8080/spring-hibernate-many-to-one-jointable/krams/main/record/list

You should see the following application:


Conclusion

That's it. We've successfully expanded our previous project Spring - Hibernate: Many-To-One Association by explicitly specifying the join table and join columns. We also declared the Cascade and Fetch strategies explicitly.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-hibernate-annotations-integration-tutorial/

You can download the project as a Maven build. Look for the spring-hibernate-many-to-one-jointable.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring - Hibernate: Many-To-One Association - Explicitly Specify Join Table, Cascade, and Fetch ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

10 comments:

  1. Hello,
    please how to see the creditCard in another page for each person. Thanks

    ReplyDelete
  2. getting No mapping found for HTTP request error, i dont know why this is happening, it seems that spring is not recognizing my annotated controllers. Any help will be appreciated!

    ReplyDelete
  3. Please post an example of processing many-to-many associations using spring/hibernate. That would be of great help & will actually cover all types of associations.

    ReplyDelete
  4. Hi,
    Do you know, if we can post a json object to a spring controller? If so, what do we expect the datattype in the request mapping or request variable

    ReplyDelete
  5. @Anonymous3, I will do it once I have the extra time. Right now, I'm working with other projects :)

    @Anonymous4, yes, you can. Check this blog: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/ You might need to check the jQuery postJSON plugin as well

    ReplyDelete
  6. Its a acceptable information and i would like to thank you for the efforts which you have made in fabricated this article.Thank you for sharing such a nice information.

    web hosting in india

    ReplyDelete
  7. Any example of saving a foreign key value by using spring form ? e.g. let’s say you have one Category to many Products. After saving categories when you come to save a product you’ll have categories as a dropdown list, so you’ll be saving a product with category id as a foreign key.

    ReplyDelete
    Replies
    1. Maybe you can look at my latest tutorial "Spring Social Tutorial" and see how I've implemented the User and Role association and how I've displayed the roles on the HTML page.

      Delete
  8. I'm very glad to read this post and i love to read this type of post, thank you so much for sharing.
    Web Hosting In India

    ReplyDelete
  9. I have read your blog its very attractive and impressive. I like it your blog.

    Spring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training

    spring training in chennai spring hibernate training in chennai

    ReplyDelete