JPA, Hibernate Composite Embeddable Primary Key

Many a times there is a need for composite key as primary key, JPA, Hibernate provides composite-key for implementing this use case.

Let’s run through this example quickly.

Step 1:

Create a “Java Project” in Eclipse and add required jars. Since Maven is nice but not a panacea, please see the image below so as to see which all jars are required.

Required Jars
Step 2:

Let’s say our model is to update Student Record, our table Student has three fields namely:

  1. Id
  2. Name
  3. Address

As per domain, both id and name are part of primary key.

Database Model


Third we need an JPA Entity class for holding Student.

Student.java

package com.mumz.test.jpa.embedded;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "STUDENT")
public class Student {
	private StudentPK	 studentPK	= null;
	private String	address	= null;
	public Student(StudentPK studentPK, String address) {
		super();
		this.studentPK = studentPK;
		this.address = address;
	}
	
	/**
	 * @param studentPK
	 *            the studentPK to set
	 */
	public void setStudentPK(StudentPK studentPK) {
		this.studentPK = studentPK;
	}
	
	/**
	 * @return the studentPK
	 */
	@Id
	public StudentPK getStudentPK() {
		return studentPK;
	}
	
	/**
	 * @return the address
	 */
	@Column(name = "STUDENT_ADDRESS")
	public String getAddress() {
		return address;
	}
	
	/**
	 * @param address
	 *            the address to set
	 */
	public void setAddress(String address) {
		this.address = address;
	}
	
	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((studentPK == null) ? 0 : studentPK.hashCode());
		result = prime * result + ((address == null) ? 0 : address.hashCode());
		return result;
	}
	
	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Student)) {
			return false;
		}
		Student other = (Student) obj;
		if (studentPK == null) {
			if (other.studentPK != null) {
				return false;
			}
		} else if (!studentPK.equals(other.studentPK)) {
			return false;
		}
		if (address == null) {
			if (other.address != null) {
				return false;
			}
		} else if (!address.equals(other.address)) {
			return false;
		}
		return true;
	}
}

You would have noticed instead of marking both id and name with @Id annotation there is another object called as studentPK of type StudentPK which has been marked with @Id annotation.

Fourth now we will see the primary key class in this case StudentPK.

StudentPK.java

package com.mumz.test.jpa.embedded;

import java.io.Serializable;

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

@Embeddable
public class StudentPK implements Serializable{
	/**
     * 
     */
    private static final long serialVersionUID = 3686950547855931594L;
	private Integer id = null;
	private String name = null;
	
    public StudentPK(Integer id, String name) {
	    this.id = id;
	    this.name = name;
    }

	/**
     * @return the id
     */
	@Column(name="STUDENT_ID")
    public Integer getId() {
    	return id;
    }
	
    /**
     * @param id the id to set
     */
    public void setId(Integer id) {
    	this.id = id;
    }
	
    /**
     * @return the name
     */
    @Column(name="STUDENT_NAME")
    public String getName() {
    	return name;
    }
	
    /**
     * @param name the name to set
     */
    public void setName(String name) {
    	this.name = name;
    }

	/** (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
	    final int prime = 31;
	    int result = 1;
	    result = prime * result + ((id == null) ? 0 : id.hashCode());
	    result = prime * result + ((name == null) ? 0 : name.hashCode());
	    return result;
    }

	/** (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
	    if (this == obj) {
		    return true;
	    }
	    if (obj == null) {
		    return false;
	    }
	    if (!(obj instanceof StudentPK)) {
		    return false;
	    }
	    StudentPK other = (StudentPK) obj;
	    if (id == null) {
		    if (other.id != null) {
			    return false;
		    }
	    } else if (!id.equals(other.id)) {
		    return false;
	    }
	    if (name == null) {
		    if (other.name != null) {
			    return false;
		    }
	    } else if (!name.equals(other.name)) {
		    return false;
	    }
	    return true;
    }
}

@Embeddable means that StudentPK is not an independent entity and it depends on another entity for it’s existence.


As per our business model, our entity class Student now has two columns namely id and name as part of primary key.

In order to run this we need to create an EntityManager which needs some configuration, generally it is called as persistence.xml.

Fifth inside META-INF folder create an xml file called as persistence.xml and fill in the value as below.

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	<persistence-unit name="myJPAService" transaction-type="RESOURCE_LOCAL">
		<class>com.mumz.test.jpa.embedded.Student</class>
		<class>com.mumz.test.jpa.embedded.StudentPK</class>
		<properties>
			<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
			<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/test"/>
			<property name="javax.persistence.jdbc.user" value="root"/>
			<property name="javax.persistence.jdbc.password" value="root"/>
			<property name="show_sql" value="true"/>
		</properties>
	</persistence-unit>
</persistence>

You would have noticed we have specified our classes and also the database details, for this example we are using MySQL.

Sixth step is to save some data in database, let’s write a test class.

EmbeddableTestMainApp.java

package com.mumz.test.jpa.embedded;

import javax.persistence.EntityManager;
import javax.persistence.Persistence;

public class EmbeddableTestMainApp {
	
	public static void main(String[] args) {
		EntityManager em = Persistence.createEntityManagerFactory("myJPAService").createEntityManager();
		StudentPK studentPK = new StudentPK(1, "Test Student");
		Student student = new Student(studentPK, "Test Address");
		boolean isError = false;
		try {
			em.getTransaction().begin();
			em.persist(student);
		} catch (Exception exp) {
			exp.printStackTrace();
			isError = true;
		} finally {
			if (isError) {
				em.getTransaction().rollback();
			} else {
				em.getTransaction().commit();
			}
		}
	}
}

Final step is to create a database for our application.

CREATE DATABASE `JPA_Project_DB`;
CREATE TABLE `JPA_Project_DB`.`STUDENT` (
  `STUDENT_ID` int(11) NOT NULL,
  `STUDENT_NAME` varchar(45) NOT NULL,
  `STUDENT_ADDRESS` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`STUDENT_ID`,`STUDENT_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

That’s all, we have just learnt how to use composite key using JPA with Hibernate as the JPA implementation provider and database as MySQL.

There are 2 comments

  1. David

    Hi.
    In a mvc project, how to you get the values from a form???.

    Using @ModelAttribute justo get student_address.

    Any idea???.

    Thanks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s