14 - Association Mapping in Hebernate

14.1 Overview

In earlier chapters we discussed persisting components using <composite-element tag where the component is persist as an value type whose  life span is dependent on the parent object. We may have a collection of objects which are not value type instead are shared objects and in such case their life span cannot be dependent on the parent object. In such cases, the contained objects will have their own identifier and hence their own lifecycle.  

In this chapter we will discuss following types of association mapping.

  1. Many to One
  2. One to Many
  3. Many to Many
  4. One to One

We will use below hibernate.cfg.xml in this entire chapter

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

     <session-factory>

       <property name="hibernate.connection.url">
            jdbc:mysql://localhost:3306/tutorial
        </property>
        <property name="hibernate.connection.username">
            root
        </property>
        <property name="hibernate.connection.password">
            password
        </property>
        <property name="dialect">  
                   org.hibernate.dialect.MySQLDialect
        </property>

        <property name="hibernate.format_sql">true</property>        
        <property name="show_sql">true</property>

        <property name="hibernate.connection.driver_class">
                com.mysql.jdbc.Driver
        </property>   
        <mapping resource="association-mapping.hbm.xml" />
     </session-factory>
</hibernate-configuration>

14.2 Many to One –

Think of the Cricket match and Stadium relationship where a multiple matches can be played at a single stadium. This is  a Many to One association from Match  to Stadium. In this scenario right now we are thinking from Match to stadium,  which means we can navigate to stadium through match  so this is a unidirectional association.

Hibernate does provide a <many-to-one> tag which can be used to map Many to One association.

From database design perspective, association is implemented by having a column in table representing “many” part of the relationship to hold the primary key of another table. This way this column is a foreign key.

In our example, Cricket_Match table will have an extra column to hold the stadium_ids 

Let's design our Entity classes.

Stadium.java

package com.tutorial.hibernate;

public  class Stadium {

      private int id;
      private String name;
      private String country;
      private int capacity;

      public int getId() {
        return id;
      }
      public void setId(int id) {
        this.id = id;
      }
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
      public String getCountry() {
        return country;
      }
      public void setCountry(String country) {
        this.country = country;
      }
      public int getCapacity() {
        return capacity;
      }
      public void setCapacity(int capacity) {
        this.capacity = capacity;
      }
      @Override
      public String toString() {
           return "Stadium [id=" + id + ", name=" + name + ", country=" + country
                + ", capacity=" + capacity + "]";
      }            
}

CricketMatch.java

package com.tutorial.hibernate;

public class CricketMatch {
   
     private int id;
     private String team1;
     private String team2;
     private String umpire;
     private String type;
     private Stadium stadium;

     public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getTeam1() {
        return team1;
    }
    public void setTeam1(String team1) {
        this.team1 = team1;
    }
    public String getTeam2() {
        return team2;
    }
    public void setTeam2(String team2) {
        this.team2 = team2;
    }
    public String getUmpire() {
        return umpire;
    }
    public void setUmpire(String umpire) {
        this.umpire = umpire;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public Stadium getStadium() {
        return stadium;
    }
    public void setStadium(Stadium stadium) {
        this.stadium = stadium;
    }
    @Override
    public String toString() {
        return "CricketMatch [id=" + id + ", team1=" + team1 + ", team2="
                + team2 + ", umpire=" + umpire + ", type=" + type
                + ", stadium=" + stadium + "]";
    }    
}

association-mapping.xml - <many-to-one> tag  is used in Cricket Match  mapping and its column attribute specifies the column name to hold the stadium ids. At the application end, we need not define an additional property corresponding to this column, hibernate does manage it internally.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.tutorial.hibernate.CricketMatch" table="Cricket_Match">
        <id name="id" type="int" column="match_id">
            <generator class="native" />
        </id>

        <property name="team1" column="team1" type="string" />
        <property name="team2" column="team2" type="string" />
        <property name="type" column="type" type="string" />    
        <property name="umpire" column="umpire" type="string" />

        <many-to-one name="stadium" class="com.tutorial.hibernate.Stadium" column="stadium_id">
        </many-to-one>
    </class>

    <class name="com.tutorial.hibernate.Stadium" table="Stadium">
        <id name="id" type="int" column="stadium_id">
            <generator class="native" />
        </id>

        <property name="name" type="string" column="stadium_name" />
        <property name="capacity" type="int" column="capacity" />
        <property name="country" type="string" column="country" />
    </class>
</hibernate-mapping>

Create Table Scripts

CREATE TABLE 'stadium' (
  'stadium_id' int(11) NOT NULL AUTO_INCREMENT,
  'stadium_name' varchar(255) DEFAULT NULL,
  'capacity' int(11) DEFAULT NULL,
  'country' varchar(255) DEFAULT NULL,
  PRIMARY KEY ('stadium_id')
);

CREATE TABLE 'cricket_match' (
  'match_id' int(11) NOT NULL AUTO_INCREMENT,
  'team1' varchar(255) DEFAULT NULL,
  'team2' varchar(255) DEFAULT NULL,
  'type' varchar(255) DEFAULT NULL,
  'umpire' varchar(255) DEFAULT NULL,
  'stadium_id' int(11) DEFAULT NULL,
  PRIMARY KEY ('match_id'),
  KEY 'FK' ('stadium_id'),
  CONSTRAINT 'FK_70fxuvas8xraq7mo6rpmsekxx' FOREIGN KEY ('stadium_id') REFERENCES 'stadium' ('stadium_id')
);

Test Program – Below is the test program to insert and retrieve the data.  In below program I have highlighted two statements and they are for saving Stadium and Cricket Match. Don’t you think that save call for  stadium is unnecessary? Ideally it should be managed by Cricket save call only. To avoid unnecessary calls, there are cascade operations which we will discuss in upcoming chapters.

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.tutorial.hibernate.CricketMatch;
import com.tutorial.hibernate.Stadium;

public class Test {

     private static SessionFactory factory;       
     public static void main(String args[])
     {
        Configuration cfg = new Configuration().configure();
        factory = cfg.buildSessionFactory();
       
        Session session = factory.openSession();
        Transaction tx = session.beginTransaction();

        Stadium stadium = new Stadium();

        stadium.setCapacity(2300);
        stadium.setCountry("Australia");
        stadium.setName("Sydney");

        CricketMatch match = new CricketMatch();

        match.setTeam1("India");
        match.setTeam2("Australia");
        match.setType("Test Match");
        match.setUmpire("Billy Bowden");
        match.setStadium(stadium);

        session.save(stadium);
        int matchId = (Integer)session.save(match);

        tx.commit();
        session.close();

        getMatchDetails(matchId);

        factory.close();        
    }

    private static void getMatchDetails(int id)
    {
        Session session = factory.openSession();        
        CricketMatch match = (CricketMatch)session.get(CricketMatch.class,id);        
        Stadium stadium = match.getStadium();
        System.out.println(match);
        System.out.println(stadium);
    }
}

Run Test Program – On running test program, console output and database states are as follows 

 

Cricket_Match table

Stadium Table

 

Like us on Facebook