In our previous articles we have seen, one to one mapping, one to many mapping and many to many mapping, in this article we will see how to map a inheritance class structures with JPA. There are three major strategies for doing this.

1) Table per hierarchy
2) Table per concrete class
3) Table per subclass

In this particular article we will see Table per subclass strategy to map inheritance structure, we have a abstract class Quiz with two implementations PracticeQuiz and GradeQuiz. Lets see how to map them using Table per concrete class strategy.

1) Super class (Quiz.java)


package com.tbNext.hb.models;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Quiz {

	@Id
	@Column(name = "ID")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(name = "QUIZ_NAME")
	private String quizName;

	public Long getId() {
		return id;
	}

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

	public String getQuizName() {
		return quizName;
	}

	public void setQuizName(String quizName) {
		this.quizName = quizName;
	}
}

We have mapped QUIZ abstract class as @MappedSuperclass, this is done with the classes that do not have a mapping table in database, we neither used a @Entity here this is because classes having @MappedSuperclass are restricted to use @Entity for not being mapped directly with database.

2) Sub Class Implementation (PracticeQuiz.java)


package com.tbNext.hb.models;

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

@Entity
@Table(name = "PRACTICE_QUIZ")
@PrimaryKeyJoinColumn(name="ID")  
public class PracticeQuiz extends Quiz{

	@Column(name = "MARKS")
	private double marks;

	@Column(name = "FEEDBACK")
	private String feedBack;
	

	public PracticeQuiz(double marks, String feedBack, String quizName) {
		super();
		this.marks = marks;
		this.feedBack = feedBack;
		super.setQuizName(quizName);
	}

	public double getMarks() {
		return marks;
	}

	public void setMarks(double marks) {
		this.marks = marks;
	}

	public String getFeedBack() {
		return feedBack;
	}

	public void setFeedBack(String feedBack) {
		this.feedBack = feedBack;
	}
}

3) Sub Class Implementation (GradeQuiz.java)


package com.tbNext.hb.models;

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

@Entity
@Table(name = "GRADE_QUIZ")
@PrimaryKeyJoinColumn(name="ID")  
public class GradeQuiz extends Quiz {

	@Column(name = "GRADE")
	private double grade;

	@Column(name = "ATEMPT_NO")
	private int attemptNo;

	public GradeQuiz(double grade, int attemptNo,String quizName) {
		super();
		this.grade = grade;
		this.attemptNo = attemptNo;
		super.setQuizName(quizName);
	}

	public double getGrade() {
		return grade;
	}

	public void setGrade(double grade) {
		this.grade = grade;
	}

	public int getAttemptNo() {
		return attemptNo;
	}

	public void setAttemptNo(int attemptNo) {
		this.attemptNo = attemptNo;
	}
}


Implementation

Now lets implement the strategy, we will try to insert PracticeQuiz and GradeQuiz in the db. There should be two different tables created in db for both sub classes.

package com.tbNext.java;

import javax.persistence.EntityManager;

import com.tbNext.hb.Utils.PersistenceManager;
import com.tbNext.hb.models.GradeQuiz;
import com.tbNext.hb.models.PracticeQuiz;
import com.tbNext.hb.models.Quiz;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) {
		// getting instance of EntityManagerFactory
		EntityManager em = PersistenceManager.INSTANCE.getEntityManager();
		
		// create practice quiz
		Quiz practiceQuiz = new PracticeQuiz(76, "excellent", "Mathematics");

		// create grade quiz
		Quiz gradeQuiz = new GradeQuiz(.7, 2, "Mathematics");

		// Adding entities to db
		em.getTransaction().begin();
		em.persist(practiceQuiz);
		em.persist(gradeQuiz);
		em.getTransaction().commit();

		// Adding entities to db
		em.getTransaction().begin();
		Quiz practiceQuizFromDb = em.find(PracticeQuiz.class,
				practiceQuiz.getId());
		System.out.println(practiceQuizFromDb);
		Quiz gradeQuizFromDb = em.find(GradeQuiz.class, gradeQuiz.getId());
		System.out.println(gradeQuizFromDb);
		em.getTransaction().commit();

	}
}


Output: Here is expected output we can see only two tables are created in db for both sub classes.

Hibernate: create table GRADE_QUIZ (ID bigint not null auto_increment, QUIZ_NAME varchar(255), ATEMPT_NO integer, GRADE double precision, primary key (ID)) ENGINE=InnoDB
Hibernate: create table PRACTICE_QUIZ (ID bigint not null auto_increment, QUIZ_NAME varchar(255), FEEDBACK varchar(255), MARKS double precision, primary key (ID)) ENGINE=InnoDB
Sep 13, 2015 6:54:57 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into PRACTICE_QUIZ (QUIZ_NAME, FEEDBACK, MARKS) values (?, ?, ?)
Hibernate: insert into GRADE_QUIZ (QUIZ_NAME, ATEMPT_NO, GRADE) values (?, ?, ?)
com.tbNext.hb.models.PracticeQuiz@ebaa6cb
com.tbNext.hb.models.GradeQuiz@6d9f7a80


Following is the structure of generated tables in database, only two tables for sub classes are created.

PRACTICE_QUIZ

typeIDQUIZ_NAMEFEEDBACKMARKS
practiceQuiz1Mathematicsexcellent76


GRADE_QUIZ

typeIDQUIZ_NAMEATEMPT_NOGRADE
gradeQuiz1Mathematics20.7


This is it for this article, we have seen how to implement inheritance strategy in JPA using table per sub class strategy. In upcoming articles we will see remaining two strategies and other useful stuff.
  • By Techburps.com
  • Oct 1, 2015
  • JPA