lishman levelup
«previous  next»


Getting Started
Associations
HQL



Hibernate Associations Quick Start


Get up and running with associations in Hibernate in just a few short steps.
The following example uses an Oracle 10g database.

1. Download

Download and install the latest Hibernate Core and Hibernate Annotations packages.

Make sure that the database driver is on the classpath.

2. Database Tables

Create and populate the database tables required for this example.
DROP TABLE visit;
DROP TABLE head_of_state;
DROP TABLE country;
DROP TABLE continent;
DROP SEQUENCE hibernate_sequence;

CREATE SEQUENCE hibernate_sequence START WITH 1000;

CREATE TABLE continent (
  cont_id    NUMBER        NOT NULL,
  cont_name  VARCHAR2(20)  NOT NULL,
  CONSTRAINT continent_pk PRIMARY KEY (cont_id),
  CONSTRAINT continent_uk UNIQUE (cont_name)
);

INSERT INTO continent (cont_id, cont_name) VALUES (1, 'Africa');
INSERT INTO continent (cont_id, cont_name) VALUES (2, 'Asia');
INSERT INTO continent (cont_id, cont_name) VALUES (3, 'Europe');
INSERT INTO continent (cont_id, cont_name) VALUES (4, 'North America');
INSERT INTO continent (cont_id, cont_name) VALUES (5, 'South America');
INSERT INTO continent (cont_id, cont_name) VALUES (6, 'Oceania');
INSERT INTO continent (cont_id, cont_name) VALUES (7, 'Antarctica');
COMMIT;

CREATE TABLE country (
  ctry_id       NUMBER        NOT NULL,
  cont_id       NUMBER        NOT NULL,
  ctry_name     VARCHAR2(50)  NOT NULL,
  area          NUMBER        NOT NULL,
  CONSTRAINT country_pk PRIMARY KEY (ctry_id),
  CONSTRAINT country_uk UNIQUE (ctry_name),
  CONSTRAINT country_fk FOREIGN KEY (cont_id) REFERENCES continent
);

INSERT INTO country (ctry_id, cont_id, ctry_name, area)
VALUES(14, 3, 'Germany', 137882);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(48, 1, 'Ghana', 92100);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(53, 6, 'Australia', 2969907);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(73, 3, 'Greece', 50949);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(122, 3, 'Georgia', 26900);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(123, 6, 'New Zealand', 104428);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(147, 1, 'Gambia', 4361);
INSERT INTO country (ctry_id, cont_id, ctry_name, area)
  VALUES(149, 1, 'Gabon', 103347);
COMMIT;

CREATE TABLE head_of_state (
  hos_id              NUMBER        NOT NULL,
  ctry_id             NUMBER        NOT NULL,
  hos_name            VARCHAR2(50)  NOT NULL,
  CONSTRAINT head_of_state_pk PRIMARY KEY (hos_id),
  CONSTRAINT head_of_state_uk UNIQUE (ctry_id),
  CONSTRAINT head_of_state_fk FOREIGN KEY (ctry_id) REFERENCES country
);

INSERT INTO head_of_state (hos_id, ctry_id, hos_name)
  VALUES (1, 122, 'President Mikheil Saakashvili');
INSERT INTO head_of_state (hos_id, ctry_id, hos_name)
  VALUES (2, 14, 'President Horst Köhler');
INSERT INTO head_of_state (hos_id, ctry_id, hos_name)
  VALUES (3, 73, 'President Karolos Papoulias');
COMMIT;

CREATE TABLE visit (
  ctry_id           NUMBER  NOT NULL,
  hos_id            NUMBER  NOT NULL,
  CONSTRAINT visit_pk PRIMARY KEY (ctry_id, hos_id),
  CONSTRAINT country_fk1 FOREIGN KEY (ctry_id) REFERENCES country,
  CONSTRAINT country_fk2 FOREIGN KEY (hos_id) REFERENCES head_of_state
);

INSERT INTO visit (ctry_id, hos_id) VALUES (14, 3);
INSERT INTO visit (ctry_id, hos_id) VALUES (48, 3);
INSERT INTO visit (ctry_id, hos_id) VALUES (149, 3);
INSERT INTO visit (ctry_id, hos_id) VALUES (73, 2);
INSERT INTO visit (ctry_id, hos_id) VALUES (73, 1);
COMMIT;

3. Hibernate Configuration File

Create a Hibernate configuration file named hibernate.cfg.xml in the root of your classpath. This is the same file as the one we created in Hibernate Quick Start except for the mapped entites at the end.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>

    <!-- Database dialect -->
    <property name="dialect">
      org.hibernate.dialect.Oracle10gDialect
    </property>

    <!-- Database connection settings -->
    <property name="connection.provider_class">
      org.hibernate.connection.C3P0ConnectionProvider
    </property>
    <property name="connection.driver_class">
      oracle.jdbc.driver.OracleDriver
    </property>
    <property name="connection.url">
      jdbc:oracle:thin:@localhost:1521:test01
    </property>
    <property name="connection.username">lish</property>
    <property name="connection.password">secret</property>

    <!-- C3P0 connection pool -->
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">50 </property>
    <property name="hibernate.c3p0.idle_test_period">3000 </property>

    <!-- Enable Hibernate's automatic session context management -->
    <property name="current_session_context_class">thread</property>

    <!-- Print all generated SQL to the console -->
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>

    <!-- Mapped entities -->
    <mapping class="levelup.world.associations.Continent"/>
    <mapping class="levelup.world.associations.Country"/>
    <mapping class="levelup.world.associations.HeadOfState"/>

  </session-factory>
</hibernate-configuration>
Be sure to change the connection settings (url, username, password) for your database.

4. HibernateUtil

Create the HibernateUtil helper class. This is exactly the same as the one we created in Hibernate Quick Start
package levelup.world;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil {

  private static SessionFactory sessionFactory;

  static {
  try {

    sessionFactory =
      new AnnotationConfiguration()
          .configure()
          .buildSessionFactory();

  } catch (Throwable ex) {
    System.err.println("Initial SessionFactory creation failed." + ex);
    throw new ExceptionInInitializerError(ex);
  }
  }

  public static SessionFactory getSessionFactory() {
  return sessionFactory;
  }

  public static void shutdown() {
  getSessionFactory().close();
  }
}

5. Continent Class

Create the Continent class.
package levelup.world.associations;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import levelup.world.HibernateUtil;

import org.hibernate.Session;


@Entity
@Table(name="CONTINENT")
public class Continent {

  @Id
  @GeneratedValue
  @Column(name="CONT_ID")
  private Integer id;

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

  @OneToMany(mappedBy = "continent",
       cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
  @org.hibernate.annotations.Cascade( {org.hibernate.annotations.CascadeType.SAVE_UPDATE})
  @JoinColumn(name = "CONT_ID")
  private Set<Country> countries = new HashSet<Country>();

  public Integer getId() {
  return id;
  }

  public void setName(String name) {
  this.name = name;
  }

  public String getName() {
  return name;
  }

  public Set<Country> getCountries() {
  return countries;
  }

  public void addCountry(Country country) {
  country.setContinent(this);
  getCountries().add(country);
  }

  public static void main(String[] args) {

  // Transitive persistence
  // Automatically save Serbia when it is added to Europe
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();

  Country serbia = new Country();
  serbia.setName("Serbia");
  serbia.setArea(34116);

  Continent europe = (Continent) session.load(Continent.class, 3);
  europe.addCountry(serbia);
  // No need to save the country explicitly.

  System.out.println(serbia.getName() + " has been added to " +
             serbia.getContinent().getName());

  session.getTransaction().commit();


  // One-to-many association
  // Display all the countries in Africa
  session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();

  Continent africa = (Continent) session.load(Continent.class, 1);

  System.out.println(africa.getName() + " has " +
             africa.getCountries().size() +
             " countries which are");
  for (Country country : africa.getCountries()) {
    System.out.println("  " + country.getName());
  }

  session.getTransaction().commit();


  // Cascading delete
  // Delete a continent and all the associated countries
  session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();

  Continent oceania = (Continent) session.load(Continent.class, 6);
  System.out.println("Oceania has " + oceania.getCountries().size() +
             " countries which are about to be deleted");

  session.delete(oceania);
  // No need to delete the countries explicitly.

  session.getTransaction().commit();

  HibernateUtil.shutdown();

  }

}

6. Country Class

Create the Country class.
package levelup.world.associations;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

import levelup.world.HibernateUtil;

import org.hibernate.Session;


@Entity
@Table(name="COUNTRY")
public class Country {

  @Id
  @GeneratedValue
  @Column(name="CTRY_ID")
  private Integer id;

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

  private int area;

  @Transient
  private int rank;

  @ManyToOne
  @JoinColumn(name = "CONT_ID")
  private Continent continent;

  @OneToOne (mappedBy="country")
  @JoinColumn(name = "CTRY_ID")
  private HeadOfState headOfState;

  @ManyToMany(mappedBy="visited")
  private Set<HeadOfState> visitors = new HashSet<HeadOfState>();

  public Integer getId() {
  return id;
  }

  public void setName(String name) {
  this.name = name;
  }

  public String getName() {
  return name;
  }

  public void setArea(int area) {
  this.area = area;
  }

  public int getArea() {
  return area;
  }

  public void setRank(int rank) {
  this.rank = rank;
  }

  public int getRank() {
  return rank;
  }

  public Continent getContinent() {
  return continent;
  }

  public void setContinent(Continent continent) {
  this.continent = continent;
  }

  public void setHeadOfState(HeadOfState headOfState) {
  this.headOfState = headOfState;
  }

  public HeadOfState getHeadOfState() {
  return headOfState;
  }

  public Set<HeadOfState> getVisitors() {
  return visitors;
  }

  public void addHeadOfState(HeadOfState headOfState) {
  headOfState.setCountry(this);
  setHeadOfState(headOfState);
  }

  public static void main(String[] args) {

  // Many-to-one, one-to-one and many-to-many associations
  // Display details about a country
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();

  Country greece = (Country) session.load(Country.class, 73);

  // many-to-one and one-to-one
  System.out.println(greece.getName() + " is in " + greece.getContinent().getName() +
             " and " + greece.getHeadOfState().getName() + " is the head of state");

  // many-to-many
  System.out.println(greece.getName() + " has been visited by ");
  for (HeadOfState hos : greece.getVisitors()) {
    System.out.println("  " + hos.getName() + " of " + hos.getCountry().getName());
  }

  session.getTransaction().commit();

  HibernateUtil.shutdown();

  }

}

7. HeadOfState Class

Create the HeadOfState class.
package levelup.world.associations;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import levelup.world.HibernateUtil;

import org.hibernate.Session;


@Entity
@Table(name="HEAD_OF_STATE")
public class HeadOfState {

  @Id
  @GeneratedValue
  @Column(name="HOS_ID")
  private Integer id;

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

  @OneToOne
  @JoinColumn(name = "CTRY_ID")
  private Country country;

  @ManyToMany
  @JoinTable (
  name="VISIT",
  joinColumns = {@JoinColumn(name="HOS_ID")},
  inverseJoinColumns={@JoinColumn(name="CTRY_ID")}
  )
  private Set<Country> visited = new HashSet<Country>();

  public Integer getId() {
  return id;
  }

  public void setName(String name) {
  this.name = name;
  }

  public String getName() {
  return name;
  }

  public void setCountry(Country country) {
  this.country = country;
  }

  public Country getCountry() {
  return country;
  }

  public Set<Country> getVisited() {
  return visited;
  }

  public void addVisit(Country country) {
  this.visited.add(country);
  country.getVisitors().add(this);
  }

  public static void main(String[] args) {

  // Add an entry in a many-to-many association
  // Record a visit to a Gambia by President Mikheil Saakashvili
  Session session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();

  HeadOfState saakashvili = (HeadOfState) session.load(HeadOfState.class, 1);
  Country gambia = (Country) session.load(Country.class, 147);
  saakashvili.addVisit(gambia);

  session.getTransaction().commit();


  // One-to-one, many-to-many and many-to-one associations
  // Display details about President Mikheil Saakashvili
  session = HibernateUtil.getSessionFactory().getCurrentSession();
  session.beginTransaction();

  saakashvili = (HeadOfState) session.load(HeadOfState.class, 1);

  // one-to-one
  System.out.println(saakashvili.getName() + " is head of state for " +
             saakashvili.getCountry().getName() +
             " and has visited");

  // many-to-many and many-to-one
  for (Country country : saakashvili.getVisited()) {
    System.out.println("  " + country.getName() +
             " in " + country.getContinent().getName());
  }

  session.getTransaction().commit();

  HibernateUtil.shutdown();
  }

}
The application structure should look like this.

Associations Application Structure

Run these classes to see Hibernate associations in action.
»