본문 바로가기
개발/JPA

[JPA] @OneToMany , @ManyToOne 사용하기

by 코딩하는 흰둥이 2024. 11. 15.
TEST 용 SQL
-- 학교의 반
CREATE TABLE CLASS (
    CLASS_ID 		BIGINT PRIMARY KEY IDENTITY ,
    CLASS_NAME 		VARCHAR(50) NOT NULL
);

-- 반에 속해있는 학생들
CREATE TABLE STUDENT (
    STUDENT_ID 			BIGINT PRIMARY KEY IDENTITY ,
    STUDENT_NAME 		VARCHAR(50) NOT NULL,
    CLASS_ID 			BIGINT ,
    FOREIGN KEY (CLASS_ID) REFERENCES CLASS(CLASS_ID)
);

 

 

Insert 구문은 더 보기를 클릭

더보기
INSERT INTO CLASS(CLASS_NAME) VALUES('1반');
INSERT INTO CLASS(CLASS_NAME) VALUES('2반');
INSERT INTO CLASS(CLASS_NAME) VALUES('3반');
INSERT INTO CLASS(CLASS_NAME) VALUES('4반');
INSERT INTO CLASS(CLASS_NAME) VALUES('5반');
INSERT INTO CLASS(CLASS_NAME) VALUES('6반');



INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('서준' , 1);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('지우' , 1);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('민서' , 1);

INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('윤서' , 2);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('지민' , 2);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('하린' , 2);

INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('이준' , 3);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('현우' , 3);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('유찬' , 3);

INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('시아' , 4);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('가은' , 4);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('서영' , 4);

INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('지원' , 5);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('진우' , 5);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('한결' , 5);

INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('태윤' , 6);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('우주' , 6);
INSERT INTO STUDENT(STUDENT_NAME, CLASS_ID) VALUES('은호' , 6);

 

 

 

ClassEntity
import com.example.reactpractice.entity.studentEntity.StudentEntity;
import jakarta.persistence.*;
import lombok.Data;

@Data
@Entity
@Table(name = "CLASS")
public class ClassEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long class_id;

    @Column(nullable = false)
    private String class_name;


    // mappedBy 는 join 하려는 entity 에서 설정한 명 , cascade 는 데이터의 일관성을 유지하기 위한 영속화 속성
    @OneToMany(mappedBy = "classEntity" , cascade = CascadeType.ALL)
    private List<StudentEntity> studentEntity;
}

 

@OneToMany 는 하나의 Entity 가 여러 개의 Entity 를 가지는 의미이다

Class 는 하나의 Entity 만 가지고 있으니 1:N 에서 1을 의미한다

예) 1반, 2반, 3반....

 

부모 격의 Table 에서는 

mappedBy 를 이용하여 자식 격 테이블 지정해 준다

 

 

StudentEntity
import com.example.reactpractice.entity.classEntity.ClassEntity;
import jakarta.persistence.*;
import lombok.Data;

@Data
@Entity
@Table(name = "STUDENT")
public class StudentEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long student_id;

    @Column(nullable = false)
    private String student_name;

    @ManyToOne
    // name 에는 studenet table 에서 사용하려는 외래키 컬럼 을 지정한다
    // referencedColumnName 에는 join 하려는 외래키 대상 table 컬럼 을 지정한다
    @JoinColumn(name = "class_id" , referencedColumnName = "class_id")
    private ClassEntity classEntity;
}

 

@ManyToOne  여러 개의 Entity 를 가지는 N 을 나타낸다

예) 1반 아무개, 1반 아무개, 1반 아무개 ....

 

자식 격 Table 은 외래키를 이용하여  부모 격 Table 과 연결시킨다

STUDENT Talbe 에서 생성한 CLASS_ID 는

@JoinColumn 으로 선언해 주기 때문에

따로 @Column 으로 설정하지 않아도 된다

 

 

 

 

ClassRepository
public interface ClassRepository extends JpaRepository<ClassEntity , Long> {
}

 

 

 

TEST
import java.util.List;

@RestController
@RequestMapping("/api/*")
public class JoinTestController {

    @Autowired
    private ClassRepository classRepository;

    @GetMapping("/joinTest")
    public void joinTest() throws Exception{

        // id 로 1반 조회
        ClassEntity classEntity = classRepository.findById(1L).get();

        // @OneToMany 로 join 한 StudentEntity 를 가져옴
        List<StudentEntity> students = classEntity.getStudentEntity();

        for(StudentEntity student : students){
            System.err.println("student : " + student.getStudent_name() );
        }

    }
    
}

 

 

각각 조회해서 가져오는걸 확인 할 수 있다

 

@OneToMany 일 때 

fetch = FetchType.LAZY 속성이 default 로 적용되어

현재 쿼리 로그는  각각 쿼리가 실행된 것을 확인할 수 있다

 

 


 

 

fetch = FetchType.EAGER , LAZY 속성 사용하기

 

fetch = FetchType.EAGER 속성을 설정하면

설정된 주 Entity 를 조회할 때 관련된 Entity 가 함께 조회된다

@Data
@Entity
@Table(name = "CLASS")
public class ClassEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long class_id;

    @Column(nullable = false)
    private String class_name;


    // mappedBy 는 join 하려는 entity 에서 설정한 명 , cascade 는 데이터의 일관성을 유지하기 위한 영속화 속성
    // fetch = FetchType.EAGER 는 설정된 Entity 조회 시 관련된 Entity 도 같이 조회
    @OneToMany(mappedBy = "classEntity" , cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<StudentEntity> studentEntity;
}

 

fetch = FetchType.EAGER 속성만 설정하고 조회를 실행하면

Join 해서 가져오는 것을 확인할 수 있다

 

반(ClassEntity)을 조회해서

학생(StudentEntity) 이름을 조회하느라 @OneToMany 에 

fetch = FetchType.EAGER 속성을 설정한 건데 연결된 데이터의 양이 많다면

fetch = FetchType.LAZY 속성을 이용하는 게 좋다고 한다

 

@ManyToOne 은 fetch = FetchType.EAGER 속성이 default

참고하자

 

 


 

@ManyToOne 을 기준으로 조회

 

@ManyToOnedefaultfetch = FetchType.EAGER 속성

@OneToManydefault fetch = FetchType.LAZY 속성

    @Autowired
    private StundentRepository stundentRepository;	// JpaRepository 상속만 받은 interface
    
    @GetMapping("/joinTest")
    public void joinTest() throws Exception{

        // id 로 반 조회
        StudentEntity student = stundentRepository.findById(2L).get();

        // @OneToMany 로 join 한 StudentEntity 를 가져옴
        ClassEntity classEntity = student.getClassEntity();

        System.err.println("학생 ID 2번은 className : " + classEntity.getClass_name() + " 의 " + student.getStudent_name() + " 학생입니다.");
        
    }

 

 

 

findById 로 조회할 때 

fetch = FetchType.EAGER 속성으로 Join 으로 조회를 하고

 

조회한 학생의 반 정보(getClassEntity())를 조회할 때

fetch = FetchType.LAZY 속성으로 조회된 것을 볼 수 있다

 

 


 

@OneToOne 과 @OneToMany 개념을 착각해서 

게시물을 작성했다가 다시 작성해서 올리느라

내용이 좀 두서없을 수 도 있다 

 

Entity 의 대상이 1 인지 N 인지만 제대로 기준을 잡자

'개발 > JPA' 카테고리의 다른 글

[JPA] @OneToOne 사용하기  (1) 2024.11.16
[JPA] @GeneratedValue 사용하기  (0) 2024.11.14
[JPA] Entity 설정하기  (0) 2024.11.13
[JPA] DELETE 하기(Delete , DeleteById , DeleteAll)  (0) 2024.11.12
[JPA] INSERT , UPDATE 하기(Save , SaveAll)  (0) 2024.11.11

댓글