y1551463

관계 Mapping

연관관계
a month ago
·
5 min read

연관관계

  • JPA에서 연관관계는 영속 객체 간의 관계를 뜻한다

  • 영속 객체인 엔티티 간의 연관 관계는 방향성을 가진다 (단방향, 양방향)

  • 연관 관계는 관계의 다중성에 따라 1:1(일대일), 1:N(일대다), N:M(다대다) 관계로 구분한다

  • 엔티티가 테이블과 매핑되는 것과 마찬가지로 엔티티 간의 관계는 테이블 간의 관계와 매핑된다

Student는 하나의 Major를 가진다

Major는 여러 Student에 속한다

테이블 관계 그대로 엔티티 정의

public class Student { //일부 코드

    @Id
    @GeneratedValue
    private Long studentId;
    private String name;
    private String grade;
    private Long majorId; // 테이블에 저장되는 형태 그대로 정의
}
 // 전공 생성
  Major major = new Major("Computer Science", "Engineering");
  em.persist(major);

 // 학생 생성
  Student student = new Student("kim", "3");
  student.setMajorId(major.getMajorId());
  em.persist(student);

  em.flush();
  em.clear();

 // 학생의 전공 찾기
  Student foundStudent = em.find(Student.class, 1);
  Major foundMajor = em.find(Major.class, foundStudent.getMajorId());
  System.out.println(foundStudent);
  System.out.println(foundMajor);

  tx.commit();

테이블 연관관계 그대로 엔티티(필드 타입)를 구성

  • foundStudent로 찾아온 학생 정보에는 전공의 정보는 포함되지 않고 fk 값이 포함된다

  • 학생의 전공을 찾기 위해서는 학생 객체의 majorId 필드를 이용해 DB를 한번 더 다녀와야 한다

  • majorId 필드를 Long 타입으로 지정하는 건 외래키를 단순히 값으로 처리하는 방식

  • 즉 객체지향 설계에서 연관관계를 객체 간에 직접 맺어주는 것이 아니라 DB 값만 이용하는 방식으로 실제 객체들 간의 관계를 반영하지 못한다 (두 객체가 서로 연결되었다고 보기 어려움) 또한 지연로딩을 활용할 수 없음 (em.find())

Student 필드에 FK를 Major 객체로 지정

    @ManyToOne// 관계구성
    @JoinColumn(name = "MAJORID") // 외래키 지정
    private Major major;

영속 객체 간의 관계는 방향성을 갖는다

Student 클래스가 Major 클래스를 참조하여 Student -> Major의 방향성을 갖게 된다

Student 객체는 참조하는 major를 통해 Major 인스턴스 객체에 접근할 수 있다

Student 클래스는 Major 클래스와 ManyToOne 관계가 된다 (N:1)

(반대 경우는 OneToMany)

 // 전공 생성
  Major major = new Major("Computer Science", "Engineering");
  em.persist(major);

 // 학생 생성
  Student student = new Student("kim", "3");
  student.setMajor(major);
  em.persist(student);

  em.flush();
  em.clear();

 // 학생의 전공 찾기
  Student foundStudent = em.find(Student.class, 1);
  System.out.println(foundStudent); // 학생 검색 시 major 에 대한 정보 함께 포함

지연로딩 설정

    @ManyToOne(fetch = FetchType.LAZY)// 관계구성
    @JoinColumn(name = "MAJORID") // 외래키 지정
    private Major major;
 // 전공 생성
  Major major = new Major("Computer Science", "Engineering");
  em.persist(major);

 // 학생 생성
  Student student = new Student("kim", "3");
  student.setMajor(major);
  em.persist(student);

  em.flush();
  em.clear();

 // 학생의 전공 찾기
  Student foundStudent = em.find(Student.class, 1);
  foundStudent.getName(); // Student 에 대한 select  발생
  System.out.println(foundStudent.getMajor().getCategory()); // Major 에 대한 select 밠생

Student 필드에 FK를 Major 객체로 저장

Student 객체에 Major 객체 자체가 포함이 된다

학생의 전공을 찾기 위해 불필요한 find를 하지 않아도 되며 실제 객체의 관계가 반영되었음을 알 수 있다

지연로딩 설정

fetch = FetchType.LAZY를 적용한 뒤에 똑같이 student를 find할 때 Student에 대한 조회 쿼리가 발생하고 이후 Major를 확인할 때 Major 조회 쿼리가 발생한다

지연로딩을 적용하면 해당 객체가 필요한 순간에 쿼리를 발생한다 (불필요한 쿼리는 보내지 않을 수 있다) 반대로 EAGER 옵션을 통해 즉시로딩도 설정할 수 있다


- 컬렉션 아티클