Course
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Course {
@Id
@SequenceGenerator(
name = "course_sequence",
sequenceName = "course_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_sequence"
)
private Long courseId;
private String title;
private Integer credit;
}
CourseMaterial
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CourseMaterial {
@Id
@SequenceGenerator(
name = "course_material_sequence",
sequenceName = "course_material_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_material_sequence"
)
private Long courseMaterialId;
private String url;
@OneToOne
@JoinColumn(
name = "course_id",
referencedColumnName = "courseId"
)
private Course course;
}
(1) @OneToOne : RelationShip 지정
(2) @JoinColumn : FK 컬럼 지정 및 이름 설정
테스팅
@SpringBootTest
class CourseMaterialRepositoryTest {
@Autowired
private CourseMaterialRepository repository;
@Test
public void SaveCourseMatarial() {
Course course = Course.builder()
.title("Math")
.credit(10)
.build();
CourseMaterial courseMaterial =
CourseMaterial.builder()
.url("www.naver.com")
.course(course)
.build();
repository.save(courseMaterial);
}
}
What is Cascaidng ?
CourseMaterial
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CourseMaterial {
@Id
@SequenceGenerator(
name = "course_material_sequence",
sequenceName = "course_material_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_material_sequence"
)
private Long courseMaterialId;
private String url;
@OneToOne(
cascade = CascadeType.ALL
)
@JoinColumn(
name = "course_id",
referencedColumnName = "courseId"
)
private Course course;
}
CascadeType.ALL
(1) Cascade Type PERSIST propagates the persist operation from a parent to a child entity.
(2) So, When we save the CourseMaterail entity, the Course entity will also get saved.
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString(exclude = "course")
public class CourseMaterial {
@Id
@SequenceGenerator(
name = "course_material_sequence",
sequenceName = "course_material_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_material_sequence"
)
private Long courseMaterialId;
private String url;
@OneToOne(
cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
@JoinColumn(
name = "course_id",
referencedColumnName = "courseId"
)
private Course course;
}
(1) FetchType.LAZY : 데이터 조회 시, 선택한 Entity만 조회
(2) FetchType.EAGER : 데이터 조회 시, 연관된 모든 Enitity 조회
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Course {
@Id
@SequenceGenerator(
name = "course_sequence",
sequenceName = "course_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_sequence"
)
private Long courseId;
private String title;
private Integer credit;
@OneToOne(
mappedBy = "course"
)
private CourseMaterial courseMaterial;
}
(1) @JoinColumn : The annotiation indicates that this entity is the owner of the relationship(FK 소유)
(2) mappedBy : mappedBy indicates that the entity in the inverse of the side relationship. this also means that we can access the other table from the class which we have annotated with "mappedBy"
=> Perform fully bidirectional relationship
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Teacher {
@Id
@SequenceGenerator(
name = "teacher_sequence",
sequenceName = "teacher_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "teacher_sequence"
)
private Long teacherId;
private String firstName;
private String lastName;
@OneToMany(
cascade = CascadeType.ALL
)
@JoinColumn(
name = "teacher_id",
referencedColumnName = "teacherId"
)
private List<Course> courses;
}
테스팅
@SpringBootTest
class TeacherRepositoryTest {
@Autowired
private TeacherRepository teacherRepository;
@Test
public void saveTeacher() {
Course courseDBA = Course.builder()
.title("DBA")
.credit(11)
.build();
Course courseJAVA = Course.builder()
.title("JAVA")
.credit(4)
.build();
Teacher teacher =
Teacher.builder()
.firstName("HEEDO")
.lastName("CHE")
.courses(List.of(courseDBA, courseJAVA))
.build();
teacherRepository.save(teacher);
}
}
Course 엔티티에 ManyToOne 적용
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Teacher {
@Id
@SequenceGenerator(
name = "teacher_sequence",
sequenceName = "teacher_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "teacher_sequence"
)
private Long teacherId;
private String firstName;
private String lastName;
}
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Course {
@Id
@SequenceGenerator(
name = "course_sequence",
sequenceName = "course_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_sequence"
)
private Long courseId;
private String title;
private Integer credit;
@OneToOne(
mappedBy = "course"
)
private CourseMaterial courseMaterial;
@ManyToOne(
cascade = CascadeType.ALL
)
@JoinColumn(
name = "teacher_id",
referencedColumnName = "teacherId"
)
private Teacher teacher;
}
테스팅
@SpringBootTest
class CourseRepository {
@Autowired
private CourseRepository courseRepository;
@Test
public void saveCourseWithTeacher() {
Teacher teacher = Teacher.builder()
.firstName("JISUB")
.lastName("LIM")
.build();
Course course = Course
.builder()
.title("Python")
.credit(8)
.teacher(teacher)
.build();
courseRepository.save(course);
}
}
1) Course Pagination
테스팅
@SpringBootTest
class CourseRepository {
@Autowired
private CourseRepository courseRepository;
@Test
public void findAllPagination() {
Pageable firstPageWithThreeRecord =
PageRequest.of(0, 3);
Pageable secondPageWithTwoRecords =
PageRequest.of(1,2);
List<Course> courses =
courseRepository.findAll(firstPageWithThreeRecord).getContent();
long totalElements =
courseRepository.findAll(firstPageWithThreeRecord).getTotalElements();
long totalPages =
courseRepository.findAll(firstPageWithThreeRecord).getTotalPages();
// 전체 행 count
System.out.println("totalElements = " + totalElements);
// 전체 page count
System.out.println("totalPages = " + totalPages);
// page 행
System.out.println("courses = " + courses);
}
}
(1) Create or obtain a PageRequest object, which is an implementation of the Pageable inteface
(2) Pass the PageRequest object as an argument to the repository method we intend to use like size, sort and etc..
2) Course Pagination & Sorting
테스팅
@SpringBootTest
class CourseRepository {
@Autowired
private CourseRepository courseRepository;
@Test
public void findAllSorting() {
Pageable sortByTitle =
PageRequest.of(0, 2, Sort.by("title"));
Pageable sortByCredit =
PageRequest.of(0,2,Sort.by("credit").descending());
Pageable sortByTitleAndCreditDesc =
PageRequest.of(
0,2,Sort.by("title").descending().and(Sort.by("credit"))
);
List<Course> courses
= courseRepository.findAll(sortByTitle).getContent();
System.out.println("courses = " + courses);
}
}
3) Course Pagination & Sorting using repository
Repository
@Repository
public interface CourseRepository extends JpaRepository<Course, Long> {
Page<Course> findByTitleContaining(
String title,
Pageable pageRequest
);
}
테스팅
@SpringBootTest
class CourseRepository {
@Autowired
private CourseRepository courseRepository;
@Test
public void printFindByTitleContaining() {
Pageable firstPageTenRecords =
PageRequest.of(0,10);
List<Course> courses =
courseRepository.findByTitleContaining(
"D",
firstPageTenRecords
).getContent();
System.out.println("courses = " + courses);
}
}
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Course {
@Id
@SequenceGenerator(
name = "course_sequence",
sequenceName = "course_sequence",
allocationSize = 1
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "course_sequence"
)
private Long courseId;
private String title;
private Integer credit;
@OneToOne(
mappedBy = "course"
)
private CourseMaterial courseMaterial;
@ManyToOne(
cascade = CascadeType.ALL
)
@JoinColumn(
name = "teacher_id",
referencedColumnName = "teacherId"
)
private Teacher teacher;
@ManyToMany(
cascade = CascadeType.ALL
)
@JoinTable(
name = "student_course_map",
joinColumns = @JoinColumn(
name = "course_id",
referencedColumnName = "courseId"
),
inverseJoinColumns = @JoinColumn(
name = "student_id",
referencedColumnName = "studentId"
)
)
private List<Student> students;
public void addStudents(Student student) {
if(students == null) students = new ArrayList<>();
students.add(student);
}
}
테스팅
@SpringBootTest
class CourseRepositoryTest {
@Autowired
private CourseRepository courseRepository;
@Test
public void saveCourseWithStudentAndTeacher() {
Teacher teacher = Teacher.builder()
.firstName("Lizze")
.lastName("KIM")
.build();
Student student = Student.builder()
.firstName("dodo")
.lastName("lee")
.emailId("dodo@gmail.com")
.build();
Course course = Course
.builder()
.title("AI")
.credit(2)
.teacher(teacher)
.build();
course.addStudents(student);
courseRepository.save(course);
}
}
참고
Spring Data JPA Tutorial | Full In-depth Course - Daily Code Buffer
https://www.baeldung.com/