Hibernate Foreign Key Example
1. Introduction
In this post, we feature a comprehensive Example on Hibernate Foreign Key. Foreign key refers to single column or group of columns in table that link data present in another table through its primary key. A Foreign key can’t exist without its parent key but viceversa is not true.
Example – A Menu can have submenus. It can be represented in tabular form as shown below where column MENU_ID
is Primary key of T_MENU
table and it is acting as Foreign Key (link between both tables) for T_SUBMENU
table:
Java Persistance Specifications provide different ways to create Foreign Key mappings as mentioned below:
1 – Using Association Mappings
2 – By Saving Collections using @ElementCollection
In this article we will show Foreign Key Creation using One to Many bi-directional Association Mapping.
Association Mapping – It is a feature provided by JPA to link two tables using below associations. Each Association can be Uni-Directional or Bi-Directional.
Association | Example |
One to One | One Person can have One Unique Identification Number |
One to Many | One Menu can have Many Sub-Menu |
Many to One | Many Sub-Menu can have One Parent Menu (Reverse of Many to One) |
Many to Many | One Student can enrol for many courses and a course can be enrolled by many students. |
2. Technologies Used
We will be building this project from scratch using following tools and technologies:
- Eclipse
- Spring Boot 1.5.10
- Maven
- Oracle
- Hibernate
- Java 8 or above
3. Create Project
We are creating Spring Boot project using Spring initializer. Steps are mentioned below:
1 – Go to http://start.spring.io/
2 – Select the following:
3 – Click on Generate Project button that will download a ready to deploy Maven project.
4 – Extract the downloaded Zip folder and paste it into your workspace.
5 – Open Eclipse -> File -> Import -> Maven -> Existing Maven Projects and select your project. Check the box(Add project(s) to working set). Finish
This spring project is ready to deploy and you can run it as Java Application in Eclipse. Now we will build our One To Many Mapping Example. For Simplicity, we’ll be creating Service, Repository and Model classes in same package – com.example.hibernateExample
.
3.1 Project Configurations
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>hibernateExample</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>hibernateExample</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.16.BUILD-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Dependencies used in pom.xml: Spring Boot MVC(spring-boot-starter-web
), Hibernate (spring-boot-starter-data-jpa
) and jaxb-api
.
application.properties
# create and drop tables and sequences, loads import.sql spring.jpa.hibernate.ddl-auto=create-drop # Oracle settings spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE spring.datasource.username= spring.datasource.password= spring.datasource.driver.class=oracle.jdbc.driver.OracleDriver # logging logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n logging.level.org.hibernate.SQL=debug
application.properties
file is present in src/main/resources
folder of a Spring Boot project. We are doing Hibernate Configurations here using Oracle JDBC driver (Since Oracle restricts automatic download of OJDBC dependency by Maven, one need to explicitly download ojdbc6.jar/ojdbc7.jar
from Oracle’s site and need to include it in ClassPath
)
3.2 Model Classes – MainMenu and SubMenu
In this section, we will design our model or entity classes using JPA and Hibernate provided annotations. Hibernate framework will be using these annotations to create tables and their Foreign Key Relationship in database. Variables of Entity class will be created as Columns in database table.
MainMenu.java
package com.example.hibernateExample; import java.io.Serializable; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.persistence.CascadeType; 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 = "T_Menu") public class MainMenu implements Serializable{ @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String description; @OneToMany(mappedBy="mainMenu", cascade = CascadeType.ALL) Set subMenu = new HashSet(); public MainMenu() { } public MainMenu(String description) { this.description = description; } // Getters and Setters (Omitted for brevity)
MainMenu
class is One(Reference) side of relationship and SubMenu
class represents Many(owning) side of relationship as ‘One Menu can have many Sub Menu’. In Database terminology, the table that has foreign key is Owner of association mapping. Let’s understand few annotations in detail which are used by Hibernate framework to create and manage Entity classes.
Line 16: @Entity
denotes the class as Entity class. Hibernate will create instance of such classes and also create table corresponding to it in database.
Line 17: @Table
is used to specify details of the table that is going to be created in database corresponding to entity class. name
attribute of this annotation allow programmer to create a table with desired name in database. If we don’t specify this annotation, table name will be same as entity class name.
Line 20: @Id
specify the variable as Primary key column for database table.
Line 21: @GeneratedValue
specify the Generation strategy for Primary Key.
Line 26: mappedBy
is used with @OnetoMany
side of association. It indicates that the entity in this side is the inverse of the relationship, and the owner resides in the “other” entity. It is used to make a relationship Bi-directional, that means the SubMenu class can be persisted or fetched through Menu class as well.
mainMenu
in mappedBy="mainMenu"
is the ManyToOne annotated field/variable of SubMenu class as shown below:
CascadeType.ALL
will perform all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH
) to the related entities/ collection e.g when Menu will be Persisted, SubMenu will also be Persisted.
SubMenu.java
package com.example.hibernateExample; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name = "T_SubMenu") public class SubMenu implements Serializable{ @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; @Column(name="SUBMENU_DESC", nullable=false, length=50) private String description; @ManyToOne @JoinColumn(name ="FK_MainMenuId") private MainMenu mainMenu; public SubMenu() { } public SubMenu(String description, MainMenu mainMenu) { this.description = description; this.mainMenu = mainMenu; } // Getters and Setters (Omitted for brevity)
Entity class SubMenu
will be used by Hibernate to create T_Submenu
table in database. @JoinColumn
annotation in line 27 indicates that this entity is the owner of the relationship (which will contain Foreign Key in Database perspective). This annotation is always used with @ManyToOne
side of association. name
attribute is used to give logical name to Foreign Key column, though it is not mandatory.
3.3 Repository Interface
MainMenuRepository.java
package com.example.hibernateExample; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface MainMenuRepository extends CrudRepository<MainMenu, Integer>{ }
In this section we are creating MainMenuRepository
interface that is a Marker interface(which doesn’t define any methods). When using Spring Data we need to define a Repository interface corresponding to each domain Entity. It will be extending Spring Data’s CrudRepository
interface which declares standard CRUD operations that can be performed on an entity. Use of CrudRepository
interface will prevent us from writing a lot of boilerplate code to access data source, writing SQL queries, Result Set etc. It will accept two parameters:
1 – Entity class corresponding to the Marker interface.
2 – Data type of Primary key defined within Entity class.
3.4 Runner
HibernateExampleApplication.java
package com.example.hibernateExample; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class HibernateExampleApplication implements CommandLineRunner { @Autowired MenuService menuService; public static void main( String[] args ) { SpringApplication.run(App.class, args); } @Override public void run(String... args) throws Exception { menuService.addMenu(); } }
HibernateExampleApplication
java class will implement CommandLineRunner
interface. This class is annotated with @SpringBootApplication
that is equivalent of using @Configuration
, @EnableAutoConfiguration
, and @ComponentScan
. We will be adding new Menus and subMenus in addMenu()
of service class, which is invoked in overrided run()
of CommandLineRunner
interface.
3.5 Service Layer
In this section we will be creating new Menus and their Sub-Menus using methods provided by Spring Data’s CrudRepository
interface. The newly created Menus and their associated Sub-Menus will be added as rows in T_menu
and T_submenu
table by Hibernate framework.
MenuService.java
package com.example.hibernateExample; public interface MenuService { public void addMenu(); }
MenuServiceImpl.java
package com.example.hibernateExample; import java.util.HashSet; import java.util.Set; import javax.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class MenuServiceImpl implements MenuService{ @Autowired MainMenuRepository mainMenuRepository; @Transactional public void addMenu(){ // For User MainMenu MainMenu menu1 = new MainMenu("User"); //Creating sub-menus for user Set subMenu1 = new HashSet(); subMenu1.add(new SubMenu("Manager", menu1)); subMenu1.add(new SubMenu("Administrator", menu1)); subMenu1.add(new SubMenu("Student", menu1)); menu1.setSubMenu(subMenu1); // For Courses MainMenu MainMenu menu2 = new MainMenu("Course"); //Creating sub-menus for user Set subMenu2 = new HashSet(); subMenu2.add(new SubMenu("B-Tech", menu2)); subMenu2.add(new SubMenu("BCA", menu2)); subMenu2.add(new SubMenu("MBA", menu2)); menu2.setSubMenu(subMenu2); // For Department MainMenu MainMenu menu3 = new MainMenu("Department"); //Creating sub-menus for user Set subMenu3 = new HashSet(); subMenu3.add(new SubMenu("Accounts", menu3)); subMenu3.add(new SubMenu("Information Technology", menu3)); subMenu3.add(new SubMenu("Sports", menu3)); menu3.setSubMenu(subMenu3); //Save MainMenu Set mainMenu = new HashSet(); mainMenu.add(menu1); mainMenu.add(menu2); mainMenu.add(menu3); mainMenuRepository.save(mainMenu); } }
addMenu()
of MenuServiceImpl
class is adding 3 MainMenu named as Course, Department and User and their submenus using CrudRepository’s save()
.
On Executing this project as a Java Application in Eclipse, we will get following output where FK_MAIN_MENU_ID
is foreign key in T_submenu
table:
ID | DESCRIPTION |
1 | Department |
5 | Course |
9 | User |
ID | SUBMENU_DESC | FK_MAIN_MENU_ID |
2 | Sports | 1 |
3 | Information Technology | 1 |
4 | Accounts | 1 |
6 | B-Tech | 5 |
7 | BCA | 5 |
8 | MBA | 5 |
10 | Manager | 9 |
11 | Student | 9 |
12 | Administrator | 9 |
4. Summary
To Summarize, we have created a Spring Boot project that is adding 3 mainMenu in T_menu
table i.e Course, Department and User. Each mainMenu can have multiple submenu which are stored in T_submenu
table. Both these tables are linked through a Foreign Key named as FK_MAIN_MENU_ID
which is created through One To Many Bidirectional mapping between MainMenu.java
and SubMenu.java
Entity classes.
5. Download the Source Code
This was an example of creating a Hibernate Foreign Key.
You can download the full source code of this example here: hibernateExample.zip
I have no idea if you guys monitor these comments but I just wanted to say you’ve saved me with this tutorial, I was having trouble finding something to explain this simple functionality! This was very clear, and very easy to extend to my own project!
I get the error:
Inferred type ‘S’ for type parameter ‘S’ is not within its bound; should extend ‘com.example.hibernateExample.MainMenu’
As I can see above in introduction
Menu can have sub_Menus
but what if we have this case
two different menus having atleast one common sub-menu
This particular confiiguration will not work