Foreign key constraint to a composite primary key in Hibernate

In this article, we will how to use Hibernate to implement the relationship where child table has composite key and one of them is a foreign key to parent table. The relational model is shown below in Figure 24.1

Figure 24.1 Figure 24.1

First create a new Java Project and configure it as Maven Project. For Reference, Click Here

Add the following dependencies in pom.xml

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
        <scope>test</scope>
    </dependency>
 
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.15</version>
    </dependency>
 
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>3.6.3.Final</version>
    </dependency>
 
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.12.1.GA</version>
    </dependency>
</dependencies>

1. Sql Script

Use the following Sql Script for creating table.

CREATE TABLE club (
  clubId INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(20) NOT NULL,
  PRIMARY KEY (ClubId)
);
  
CREATE TABLE  team (
  teamid INT(10) UNSIGNED NOT NULL,
  clubid INT(10) UNSIGNED NOT NULL,
  teamname VARCHAR(10) NOT NULL,
  PRIMARY KEY (teamid, clubid),
  FOREIGN KEY (clubid) REFERENCES club (clubid));

2. Pojo

Now create Club, Team and TeamId Class as following.

Club.java

package com.kruders.model.bean;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "club", catalog = "test")
public class Club implements java.io.Serializable {

	private Integer clubId;
	private String name;
	private Set<Team> teams = new HashSet<Team>(0);

	public Club() {
	}

	public Club(String name) {
		this.name = name;
	}

	public Club(String name, Set<Team> teams) {
		this.name = name;
		this.teams = teams;
	}

	@Id
	@GeneratedValue(strategy= GenerationType.AUTO)
	@Column(name = "clubId", unique = true, nullable = false)
	public Integer getClubId() {
		return this.clubId;
	}

	public void setClubId(Integer clubId) {
		this.clubId = clubId;
	}

	@Column(name = "name", nullable = false, length = 20)
	public String getName() {
		return this.name;
	}

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

	@OneToMany(fetch = FetchType.LAZY, mappedBy = "club")
	public Set<Team> getTeams() {
		return this.teams;
	}

	public void setTeams(Set<Team> teams) {
		this.teams = teams;
	}

}


Team.java

package com.kruders.model.bean;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name = "team", catalog = "test")
public class Team implements java.io.Serializable {

	private TeamId id;
	private Club club;
	private String teamname;

	public Team() {
	}

	public Team(TeamId id, Club club, String teamname) {
		this.id = id;
		this.club = club;
		this.teamname = teamname;
	}

	@EmbeddedId
	@AttributeOverrides({
			@AttributeOverride(name = "teamid", column = @Column(name = "teamid", nullable = false)),
			@AttributeOverride(name = "clubid", column = @Column(name = "clubid", nullable = false)) })
	public TeamId getId() {
		return this.id;
	}

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

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "clubid", nullable = false, insertable = false, updatable = false)
	public Club getClub() {
		return this.club;
	}

	public void setClub(Club club) {
		this.club = club;
	}

	@Column(name = "teamname", nullable = false, length = 10)
	public String getTeamname() {
		return this.teamname;
	}

	public void setTeamname(String teamname) {
		this.teamname = teamname;
	}

}


TeamId.java

package com.kruders.model.bean;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class TeamId implements java.io.Serializable {

	private int teamid;
	private int clubid;

	public TeamId() {
	}

	public TeamId(int teamid, int clubid) {
		this.teamid = teamid;
		this.clubid = clubid;
	}
	
	
	@Column(name = "teamid", nullable = false)
	public int getTeamid() {
		return this.teamid;
	}

	public void setTeamid(int teamid) {
		this.teamid = teamid;
	}

	@Column(name = "clubid", nullable = false)
	public int getClubid() {
		return this.clubid;
	}

	public void setClubid(int clubid) {
		this.clubid = clubid;
	}

	public boolean equals(Object other) {
		if ((this == other))
			return true;
		if ((other == null))
			return false;
		if (!(other instanceof TeamId))
			return false;
		TeamId castOther = (TeamId) other;

		return (this.getTeamid() == castOther.getTeamid())
				&& (this.getClubid() == castOther.getClubid());
	}

	public int hashCode() {
		int result = 17;

		result = 37 * result + this.getTeamid();
		result = 37 * result + this.getClubid();
		return result;
	}

}

We use the @OneToMany annotation in Club class and @ManyToOne element in TeamId class to create the one-to-many relationship between the Club and Team entities. Composite primary keys use a embedded class as the primary key representation, so we have used the @Embeddable annotation in TeamId class.

3. Hibernate Configuration File

Now create the hibernate configuration file and add all the mapping files.
hibernate.cfg.xml

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

<hibernate-configuration>
	<session-factory>
	 	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password"></property>
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<property name="show_sql">true</property>
		<mapping class="com.kruders.model.bean.Club" />
    	<mapping class="com.kruders.model.bean.Team" />
	</session-factory>
</hibernate-configuration>

4. Hibernate Utility Class

Now create HibernateUtil class. The HibernateUtil class helps in creating the SessionFactory from the Hibernate configuration file. A org.hibernate.SessionFactory is used to obtain org.hibernate.Session instances. A org.hibernate.Session represents a single-threaded unit of work. The org.hibernate.SessionFactory is a thread-safe global object that is instantiated once.

package com.kruders.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
  
public class HibernateUtil {
  
    private static final SessionFactory sessionFactory = buildSessionFactory();
  
    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
  
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

5. Run Program

Create Main.java class that insert a record in database and run it as Java Application

package com.kruders.core;

import org.hibernate.Session;

import com.kruders.model.bean.Club;
import com.kruders.model.bean.Team;
import com.kruders.model.bean.TeamId;
import com.kruders.util.HibernateUtil;


public class Main {
	public static void main(String[] args) {
		Session session = HibernateUtil.getSessionFactory().openSession();

		session.beginTransaction();

		Club club = new Club();
		club.setClubId(1);
		club.setName("Arsenal");
		
		TeamId teamId = new TeamId();
		teamId.setTeamid(1);
		teamId.setClubid(club.getClubId());
		
		Team team = new Team();
		team.setId(teamId);
		team.setClub(club);
		
		team.setTeamname("Team A");
		
		club.getTeams().add(team);
		session.save(team);
		session.save(club);
		session.getTransaction().commit();
	}
}

The folder structure of the example is shown below in Figure 24.2

Figure 24.2 Figure 24.2

You can download the source code of this example here.

No comments yet.

Leave a Reply