JPA — OneToMany foreign key mapping strategy
The above output shows that no ‘join table’ is generated, instead a foreign-key column, MY_FK_COL has been used to persist the relationship. If we don’t specify ‘name’ element of @JoinColumn, the default ENTITYBLIST_MYIDA will be used.
Following diagram gives a quick overview of the relationship
public class ExampleMain2 < public static void main(String[] args) < EntityManagerFactory emf = Persistence.createEntityManagerFactory("test1"); try < persistEntity(emf); nativeQueries(emf); loadEntityA(emf); loadEntityB(emf); >finally < emf.close(); >> private static void nativeQueries(EntityManagerFactory emf) < System.out.println("-- native queries --"); EntityManager em = emf.createEntityManager(); ExampleMain.nativeQuery(em, "Select * from EntityA"); ExampleMain.nativeQuery(em, "Select * from EntityB"); >private static void persistEntity(EntityManagerFactory emf) < EntityManager em = emf.createEntityManager(); EntityB entityB = new EntityB(); entityB.setStrB("testStringB"); EntityB entityB2 = new EntityB(); entityB2.setStrB("testStringB2"); EntityA entityA = new EntityA(); entityA.setStrA("testStringA"); entityA.setEntityBList(Arrays.asList(entityB, entityB2)); System.out.println("-- Persisting entities --"); System.out.println(entityA); em.getTransaction().begin(); em.persist(entityA); em.persist(entityB); em.persist(entityB2); em.getTransaction().commit(); em.close(); >private static void loadEntityA(EntityManagerFactory emf) < System.out.println("-- Loading EntityA --"); EntityManager em = emf.createEntityManager(); ListentityAList = em.createQuery("Select t from EntityA t").getResultList(); entityAList.forEach(System.out::println); em.close(); > private static void loadEntityB(EntityManagerFactory emf) < System.out.println("-- Loading EntityB --"); EntityManager em = emf.createEntityManager(); ListentityBList = em.createQuery("Select t from EntityB t").getResultList(); entityBList.forEach(System.out::println); em.close(); > >
Output
-- Persisting entities --
EntityA, EntityB], strA='testStringA'>
-- native queries --
--------
'Select * from EntityA'
[1, testStringA]
--------
'Select * from EntityB'
[2, testStringB, 1]
[3, testStringB2, 1]
-- Loading EntityA --
EntityA, EntityB], strA='testStringA'>
-- Loading EntityB --
EntityB
EntityB
Example Project
Dependencies and Technologies Used:
- h2 1.4.193: H2 Database Engine.
- hibernate-core 5.2.8.Final: The core O/RM functionality as provided by Hibernate.
Implements javax.persistence:javax.persistence-api version 2.1 - JDK 1.8
- Maven 3.3.9
Hibernate Foreign Key Example
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:
In order to help you master JPA and database programming with Hibernate, we have compiled a kick-ass guide with all the major Hibernate features and use cases! Besides studying them online you may download the eBook in PDF format!
Thank you!
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
- 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
4.0.0 com.example hibernateExample 0.0.1-SNAPSHOT jar hibernateExample org.springframework.boot spring-boot-starter-parent 1.5.16.BUILD-SNAPSHOT UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-data-jpa javax.xml.bind jaxb-api 2.3.0 org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
Dependencies used in pom.xml: Spring Boot MVC( spring-boot-starter-web ), Hibernate ( spring-boot-starter-data-jpa ) and jaxb-api .
# 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 %-5level %logger - %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.
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 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.
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
package com.example.hibernateExample; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; @Repository public interface MainMenuRepository extends CrudRepository
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
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.
package com.example.hibernateExample; public interface MenuService
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.