February 25th, 2023
@ManyToOne Mapping
OneToOne Unidirectional Student - Passport
@OneToMany
– Lazy Fetching-
@ManyToOne
– Eager Fetching -
@OneToOne
– Eager Fetching
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.0.2
com.brains.jpa.hibernate
jpa-hibernate-demo
0.0.1-SNAPSHOT
jpa-hibernate-demo
Demo project for Spring Boot
17
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-web
com.h2database
h2
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true
spring.jpa.defer-datasource-initialization=true
# Turn Statistics ON
#spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=debug
#logging.level.root=trace
# Show all queries
spring.jpa.show-sql=true
# Format the queries
spring.jpa.properties.hibernate.format_sql=true
Many reviews for 1 Course, here Course 10001 has 5 reviews.
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Course {
@Id
@GeneratedValue
private Long id;
private String name;
@Setter(AccessLevel.NONE)
@OneToMany(mappedBy = "course")
private List reviews = new ArrayList<>();
public void addReview(Review review) {
this.reviews.add(review);
}
public void removeReview(Review review) {
this.reviews.remove(review);
}
@UpdateTimestamp
private LocalDateTime lastUpdatedDate;
@CreationTimestamp
private LocalDateTime createdDate;
public Course(String name) {
this.name = name;
}
}
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Data @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@RequiredArgsConstructor
public class Review {
@Id
@GeneratedValue
private Long id;
@NonNull
private String rating;
@NonNull
private String description;
@ToString.Exclude
@ManyToOne
private Course course;
}
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Entity
@Data @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@RequiredArgsConstructor
public class Passport {
@Id
@GeneratedValue
private Long id;
@NonNull
@Column(nullable = false)
private String number;
@ToString.Exclude
@OneToOne(fetch = FetchType.LAZY, mappedBy = "passport")
private Student student;
}
package com.brains.jpa.hibernate.jpahibernatedemo.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Entity
@Data @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@RequiredArgsConstructor
public class Student {
@Id
@GeneratedValue
private Long id;
@NonNull
@Column(nullable = false)
private String name;
@OneToOne(fetch = FetchType.LAZY)
private Passport passport;
}
insert into course(id, name, created_date, last_updated_date)
values(10001, 'JPA in 5 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
insert into course(id, name, created_date, last_updated_date)
values(10002, 'JDBC in 10 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
insert into course(id, name, created_date, last_updated_date)
values(10003, 'JPQL in 50 steps', LOCALTIMESTAMP, LOCALTIMESTAMP);
insert into passport(id, number)
values(40001,'E12345');
insert into passport(id, number)
values(40002,'F212345');
insert into passport(id, number)
values(40003,'G12345');
insert into student(id, name, passport_id)
values(20001,'Ranga',40001);
insert into student(id, name, passport_id)
values(20002,'Adam',40002);
insert into student(id, name, passport_id)
values(20003,'Jane',40003);
insert into review(id, rating, description, course_id)
values(50001,'1', 'Great course', 10001);
insert into review(id, rating, description, course_id)
values(50002,'3', 'Nice course', 10001);
insert into review(id, rating, description, course_id)
values(50004,'5', 'Good you are writing', 10003);
package com.brains.jpa.hibernate.jpahibernatedemo.repository;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Review;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
@Repository
@Transactional
public class CourseRepository {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
EntityManager em;
public Course findById(Long id) {
return em.find(Course.class, id);
}
public void deleteById(Long id) {
Course course = findById(id);
em.remove(course);
}
public Course save(Course course) {
if(course.getId() == null) {
//insert
em.persist(course);
}else {
//update
em.merge(course);
}
return course;
}
public void playWithEntityManager() {
Course course1 = new Course("AngularJs in 100 Steps");
em.persist(course1);
Course course2 = findById(10001L);
course2.setName("JPA in 5 steps -- updated");
}
public void addHardcodedReviewsForCourse() {
Course course = findById(10003L);
logger.info("course Reviews -> {}", course.getReviews());
Review review1 = new Review("3", "Better");
Review review2 = new Review("5", "Superb");
course.getReviews().add(review1);
review1.setCourse(course);
course.getReviews().add(review2);
review2.setCourse(course);
em.persist(review1);
em.persist(review2);
logger.info("course Reviews -> {}", course.getReviews());
}
public void addDynamicReviewsForCourse(Long courseId, List reviews) {
Course course = findById(courseId);
logger.info("course Reviews -> {}", course.getReviews());
for(Review review : reviews) {
course.getReviews().add(review);
review.setCourse(course);
em.persist(review);
}
}
}
package com.brains.jpa.hibernate.jpahibernatedemo.repository;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.brains.jpa.hibernate.jpahibernatedemo.JpaHibernateDemoApplication;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Course;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.Review;
import jakarta.persistence.EntityManager;
import jakarta.transaction.Transactional;
@SpringBootTest(classes = JpaHibernateDemoApplication.class)
class CourseRepositoryTest {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
CourseRepository courseRepository;
@Autowired
EntityManager em;
@Test
@Transactional
void retrieveReviewsForCourse() {
Course course = courseRepository.findById(10001L);
logger.info("Reviews: -> {}", course.getReviews());
}
@Test
@Transactional
void retrieveCourseForReview() {
Review review = em.find(Review.class, 50001L);
logger.info("Reviews: -> {}", review);
Course course = review.getCourse();
logger.info("Course: -> {}", course);
}
}
package com.brains.jpa.hibernate.jpahibernatedemo;
import java.util.ArrayList;
import java.util.List;
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 com.brains.jpa.hibernate.jpahibernatedemo.entity.Review;
import com.brains.jpa.hibernate.jpahibernatedemo.repository.CourseRepository;
@SpringBootApplication
public class JpaHibernateDemoApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(JpaHibernateDemoApplication.class, args);
}
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private CourseRepository courseRepository;
@Override
public void run(String... args) throws Exception {
List reviews = new ArrayList<>();
reviews.add(new Review("3", "Better"));
reviews.add(new Review("5", "Superb"));
reviews.add(new Review("4", "Wow"));
courseRepository.addDynamicReviewsForCourse(10001L, reviews);
}
}
Hibernate:
select
c1_0.id,
c1_0.created_date,
c1_0.last_updated_date,
c1_0.name
from
course c1_0
where
c1_0.id=?
Hibernate:
select
r1_0.course_id,
r1_0.id,
r1_0.description,
r1_0.rating
from
review r1_0
where
r1_0.course_id=?
2023-02-25T22:10:56.790+05:30 INFO 69975 --- [ main] c.b.j.h.j.repository.CourseRepository : course Reviews -> [Review(id=50001, rating=1, description=Great course), Review(id=50002, rating=3, description=Nice course)]
Hibernate:
select
next value for review_seq
Hibernate:
select
next value for review_seq
Hibernate:
insert
into
review
(course_id, description, rating, id)
values
(?, ?, ?, ?)
Hibernate:
insert
into
review
(course_id, description, rating, id)
values
(?, ?, ?, ?)
Hibernate:
insert
into
review
(course_id, description, rating, id)
values
(?, ?, ?, ?)
Hibernate:
select
c1_0.id,
c1_0.created_date,
c1_0.last_updated_date,
c1_0.name
from
course c1_0
where
c1_0.id=?
Hibernate:
select
r1_0.course_id,
r1_0.id,
r1_0.description,
r1_0.rating
from
review r1_0
where
r1_0.course_id=?
2023-02-25T22:10:56.984+05:30 INFO 69975 --- [ main] c.b.j.h.j.r.CourseRepositoryTest : Reviews: -> [Review(id=1, rating=3, description=Better), Review(id=2, rating=5, description=Superb), Review(id=3, rating=4, description=Wow), Review(id=50001, rating=1, description=Great course), Review(id=50002, rating=3, description=Nice course)]
Hibernate:
select
r1_0.id,
c1_0.id,
c1_0.created_date,
c1_0.last_updated_date,
c1_0.name,
r1_0.description,
r1_0.rating
from
review r1_0
left join
course c1_0
on c1_0.id=r1_0.course_id
where
r1_0.id=?
2023-02-25T22:10:57.005+05:30 INFO 69975 --- [ main] c.b.j.h.j.r.CourseRepositoryTest : Reviews: -> Review(id=50001, rating=1, description=Great course)
Hibernate:
select
r1_0.course_id,
r1_0.id,
r1_0.description,
r1_0.rating
from
review r1_0
where
r1_0.course_id=?
2023-02-25T22:10:57.005+05:30 INFO 69975 --- [ main] c.b.j.h.j.r.CourseRepositoryTest : Course: -> Course(id=10001, name=JPA in 5 steps, reviews=[Review(id=1, rating=3, description=Better), Review(id=2, rating=5, description=Superb), Review(id=3, rating=4, description=Wow), Review(id=50001, rating=1, description=Great course), Review(id=50002, rating=3, description=Nice course)], lastUpdatedDate=2023-02-25T22:10:56.658209, createdDate=2023-02-25T22:10:56.658209)
Leave a Reply