The Spring Boot JPA One to Many Relationship Mapping Example shows you the process of mapping an one-to-many relationship using Spring Data JPA and Spring Boot. A OneToMany relationship in Java is where the source object has an attribute that stores a collection of target objects and if those target objects had the inverse relationship back to the source object it would be a ManyToOne relationship.
Other interesting posts you may like
Let’s begin:
Project structure
Our classic mvn project in this Spring Boot JPA One to Many Relationship Mapping Example.
Maven dependencies
Our Spring Boot JPA One to Many Relationship Mapping Example will use JPA, MySQL, so that we must add these dependencies in the pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<?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.javabycode</groupId> <artifactId>spring-boot-jpa-one-to-many-example</artifactId> <version>1.0.0-SNAPSHOT</version> <name>Spring Boot JPA One-To-Many Example</name> <description>Spring Boot JPA One-To-Many Example</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </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> |
One-To-Many Relationship
We are using a database named example_onetomany and two student and course tables . The course and student tables have a one-to-many relationship via course.id and student.course_id.
Here is the sql script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
CREATE DATABASE IF NOT EXISTS `example_onetomany`; USE `example_onetomany`; -- -- Table structure for table `student_detail` -- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`,`name`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; -- -- Table structure for table `student` -- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `course_id` int(11) unsigned DEFAULT NULL, PRIMARY KEY (`id`), KEY `fk_student_courseid_idx` (`course_id`), CONSTRAINT `fk_student_courseid` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
Create JPA Entities
Entity class Student and Course are simple POJO class. Here we are using class Student and Course with JPA @Entity annotation to map them to a database tables (these tables were created in above step).
Student Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package com.javabycode.jpa.model; import java.io.Serializable; import javax.persistence.*; @Entity public class Student implements Serializable{ private static final long serialVersionUID = -3295618803288063735L; private int id; private String name; private Course course; public Student() { } public Student(String name) { this.name = name; } public Student(String name, Course course) { this.name = name; this.course = course; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @ManyToOne @JoinColumn(name = "course_id") public Course getCourse() { return course; } public void setCourse(Course course) { this.course = course; } } |
Course Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
package com.javabycode.jpa.model; import javax.persistence.*; import java.io.Serializable; import java.util.Set; @Entity @Table(name = "course") public class Course implements Serializable{ private static final long serialVersionUID = 2165900900917717356L; private int id; private String name; private Set<Student> students; public Course(){ } public Course(String name) { this.name = name; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @OneToMany(mappedBy = "course", cascade = CascadeType.ALL) public Set<Student> getStudents() { return students; } public void setStudents(Set<Student> students) { this.students = students; } @Override public String toString() { String result = String.format( "Course[id=%d, name='%s']%n", id, name); if (students != null) { for(Student student : students) { result += String.format( "Student[id=%d, name='%s']%n", student.getId(), student.getName()); } } return result; } } |
Dig deeper:
@Table annotation maps the entity with the table. If no @Table is omitted, the default value is used. It means that the class name of the entity maps with the table.
@Id annotation marks the identifier property of the entity.
@Column application maps the entity’s field with the table’s column. If @Column is omitted, the default value is used. It means that the field name of the entity maps with the table’s column.
@OneToMany and @ManyToOne annotations define a one-to-many and many-to-one relationship between 2 entities. @JoinColumn annotation indicates the entity is the owner of the relationship(that is: the corresponding table has a column with a foreign key to the referenced table), whereas the attribute mappedBy indicates that the entity in this side is the inverse of the relationship, and the owner resides in the “other” entity.
Spring Data JPA Repository
In this example, we all need to extend the JpaRepository. This is a built-in Repository implemented some common functions to work with database: findOne, findAll, save,etc.
1 2 3 4 5 6 7 8 9 |
package com.javabycode.jpa.repository; import com.javabycode.jpa.model.Course; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface StudentCourseRepository extends JpaRepository<Course, Integer>{ } |
Properties Configuration
1 2 3 4 5 6 7 |
spring.datasource.url=jdbc:mysql://localhost/example_onetomany spring.datasource.username=javabycode spring.datasource.password=mypassword spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true |
Create SpringBootApplication class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package com.javabycode.jpa; import com.javabycode.jpa.model.Student; import com.javabycode.jpa.model.Course; import com.javabycode.jpa.repository.StudentCourseRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import javax.transaction.Transactional; import java.util.HashSet; import java.util.Set; @SpringBootApplication public class MyJpaApplication implements CommandLineRunner { private static final Logger logger = LoggerFactory.getLogger(MyJpaApplication.class); @Autowired private StudentCourseRepository studentCourseRepository; public static void main(String[] args) { SpringApplication.run(MyJpaApplication.class, args); } @Override @Transactional public void run(String... strings) throws Exception { // save a couple of courses final Course courseA = new Course("Course A"); Set studentASet = new HashSet<Student>(){{ add(new Student("Student A1", courseA)); add(new Student("Student A2", courseA)); }}; courseA.setStudents(studentASet); final Course courseB = new Course("Course B"); Set studentBSet = new HashSet<Student>(){{ add(new Student("Student B1", courseB)); add(new Student("Student B2", courseB)); }}; courseB.setStudents(studentBSet); //persit entities to database studentCourseRepository.save(new HashSet<Course>() {{ add(courseA); add(courseB); }}); // fetch all courses for (Course course : studentCourseRepository.findAll()) { logger.info(course.toString()); } } } |
DEMO
You can go to the project directory on the console screen and run the command line
1 |
mvn spring-boot:run |
Or create the unit test class, for example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.javabycode.jpa; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes=MyJpaApplication.class) public class JpaApplicationTests { @Test public void contextLoads() { } } |
Run the above test class and see the output like below
1 2 3 4 5 6 7 |
2017-04-21 10:11:31.406 INFO 5176 --- [ main] com.javabycode.jpa.MyJpaApplication : Course[id=9, name='Course B'] Student[id=1, name='Student B1'] Student[id=2, name='Student B2'] 2017-04-21 10:11:31.406 INFO 5176 --- [ main] com.javabycode.jpa.MyJpaApplication : Course[id=10, name='Course A'] Student[id=3, name='Student A2'] Student[id=4, name='Student A1'] |
That’s all on the Spring Boot JPA One to Many Relationship Mapping Example.
References
One-to-Many Relationships
ManyToOne Relationships
Spring Boot – Database initialization
Donwload complete source code, click link below
spring-boot-jpa-one-to-many-example.zip (467 downloads)