Spring boot JPA (2) - Relationship

kimkevin90·2022년 2월 6일
0

SpringBoot

목록 보기
6/6
post-thumbnail

0. 테이블 관계 요약

1. One-To-One Relationship

Entity

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);
    }
}
  • Course의 row가 없는 상태로 CourseMaterial은 생성 시, CourseMaterial은 courseId가 없으므로 오류 발생

2. Cascade Types

What is Cascaidng ?

  • When we perform some action on the target entity, the same action will be applied to the associated entity

Entity

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.

3. Fetch Types

Entity

@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 조회

4. Uni & Bi directional relationship

Entity

@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

5. JPA One-To-Many Relationship

Entity

@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);
    }
}

6. JPA Many-To-One Relationship

Entity

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);
    }
}

7. Paging and Sorting

Entity

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);
    }
}

8. JPA Many-To-Many Relationship

Entity

@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/

profile
Pay it forward

0개의 댓글