Spring Boot JPA Association Mapping With example - JPA annotations explanations

Today we will see JPA annotation and association mapping in Spring Boot JPA.

Before we start if you don't know how to create a Spring boot project and database connection, please see the below blogs to get a clear view.

Create Spring Boot Project in IDE Eclipse

Spring boot JPA integration with SQlite

Spring boot With Lombok library

JPA Annotations

JPA annotations are present in the javax.persistence package.

@Entity - This annotation is to mark a class as an entity in JPA. 

@Table - This annotation in combination with @entity. It specifies the table which contains the data for the entity. If @Table is not present, then JPA takes the class name as the table name. 

@Column - It specifies the table column to the entity field.

@Id - It's used to define the primary key of the table.

Association Mapping

What is Association Mapping in JPA?

When two entities have a relationship or association with them. In association, an entity can be an owing entity or a non-owing entity. 

An entity that contains a reference to another entity is the owning entity. Another entity that is being referred to is the non-owning entity.

If any of the entities contain the reference, then it's a unidirectional association. 

If both entities contain a reference to each other then it's called bi-directional association.

Types of Association in JPA

  1. One-to-one
  2. One-to-many
  3. Many-to-one
  4. Many-to-many

Maven dependencies

Add the following dependency to the pom.xml file.


<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Database library -->
<dependency>
	<groupId>com.zsoltfabok</groupId>
	<artifactId>sqlite-dialect</artifactId>
	<version>1.0</version>
</dependency>
<dependency>
	<groupId>org.xerial</groupId>
	<artifactId>sqlite-jdbc</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

Configuring DataSource

Now we need to configure the database connection, add the below properties in application.properties.


#Database
spring.datasource.url=jdbc:sqlite:StudentsDB.db

#logging
logging.level.root=info
#logging.level.org.hibernate.SQL=info

#Show sql commands
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.physical_naming_strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

One-to-one

First, we will see about one-to-one association mapping in JPA Hibernate. An association is one-to-one when there exists a relationship or association between two entities.

Let's create two tables like below, a student and parent table in which student and parent share the one-to-one association. A student can have a parent.

spring boot JPA one to one association mapping example

The student table contains the foreign key (parent Id) which refers to the parent table primary key. So here we are trying to map the association based on the foreign key. 

Create Entity class

In JPA, the @OneToOne annotation defines a one-to-one association.

@JoinColumn annotation when a foreign key is used to map the association between entities. 


import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Parent {

	@Id
	@Column(name ="id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int pid;
	private String fatherName;
	private String motherName;
	
}
@PrimaryKeyJoinColumn is used when two entities share the same primary key.

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Student {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	private String name;

	@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
	@JoinColumn(name = "parentid", referencedColumnName = "id")
	private Parent parent;
    
}

Cascade In JPA

Whenever the parent table gets manipulated by DB operations (insert, update, delete) the child table also with reference gets manipulated.

The cascade attributes in @JoinColumn tell JPA how the cascade between the entities happens.

There are 5 cascade types available in JPA. Here we have used CascadeType.ALL means cascade for all cascadable operations (PERSIST, MERGE, REMOVE, REFRESH, DETACH).

Create JPA Repository 

Create an interface annotated with @Repository that extends JpaRepository. These repositories contain the methods to handle the database operation.


import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.example.relational.entity.Student;

@Repository
public interface StudentRepository extends JpaRepository<Student, Integer> {

}

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.example.relational.entity.Parent;

@Repository
public interface ParentRepository extends JpaRepository<Parent, Integer> {

}


Testing DB Operation 

Let's create JUnit to test our repository using Spring boot @DataJpaTest annotation. The @DataJpaTest provides support to test the JPA repository. 

By default, all DataJpatest cases will be transactional and roll back after completion.


import static org.junit.jupiter.api.Assertions.*;

import java.util.List;
import java.util.Optional;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.relational.entity.Parent;
import com.example.relational.entity.Student;
import com.example.relational.repository.StudentRepository;

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class StudentRepositoryTest {

	@Autowired
	StudentRepository studentRepository;

	@Test
	public void addStudent() {
		Parent parent = Parent.builder().fatherName("Bharath1").motherName("Gayu1").build();
		Student student = Student.builder().name("JaiKuamr1").parent(parent).build();

		int id = studentRepository.save(student).getId();
		System.out.println("Student ID = " + id);

		Student savedStudent = studentRepository.getById(id);
		System.out.println("Student =" + savedStudent);

		assertNotNull(savedStudent);
	}

	@Test
	public void getStudentById() {
		Optional<Student> student = studentRepository.findById(2);
		System.out.println("Student =" + student.get());
		assertNotNull(student.orElseGet(null));
	}

    @Test
	public void getAllStudent() {
		List<Student> students = studentRepository.findAll();
		System.out.println("Total number of students record" + students.size());
		assertEquals(4, students.size());
	}
}

On executing the above tests we can see below logs on the console after each test the rollback is performed and the JPA query is printed for each DB operation.

java JPA association mapping example

we can see JPA one-to-many and many-to-one examples here.

Post a Comment

Previous Post Next Post

Recent Posts

Facebook