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.
Run these classes to see Hibernate associations in action.
|