241126 TIL - JPA 연관관계 매핑에 대해서

J_log·2024년 11월 26일
0
post-thumbnail

공부하면서 알게된 1:N, 1:1, N:M 관계에서 단방향과 양방향 매핑을 어떻게 설정하고 각각의 장단점은 무엇인지 정리해보았다. 아직도 잘 이해가 되지않지만 정리하면서 또 복습해보자

1:N(OneToMany)

  1. 단방향 1:N
  • 한 엔티티가 여러 엔티티와 관계를 가질 수 있는 경우
@Entity
public class Post {
    @Id @GeneratedValue
    private Long id;

    @OneToMany
    @JoinColumn(name = "post_id") // Comment 테이블에 FK를 생성
    private List<Comment> comments = new ArrayList<>();
}
  • 특징

    • 관계를 Post -> Comment 방향으로만 관리
    • 상대방(Comment)에서는 Post의 정보를 알 수 없음
  • 장단점

    • 장점 : 간단하고 사용하기 쉽다.
    • 단점 : 외래 키를 관리하는 주체가 컬렉션(List)에 있기 때문에 JPA가 추가적인 SQL 쿼리를 생성한다.

  1. 양방향 1:N
  • 양쪽에서 서로의 관계를 참조하는 경우
@Entity
public class Post {
    @Id @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "post")
    private List<Comment> comments = new ArrayList<>();
}

@Entity
public class Comment {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "post_id")
    private Post post;
}
  • mappedBy를 사용해 연관 관계의 주인을 Comment로 설정

  • Post는 단순히 관계를 조회하는 역할(Read-Only)

  • 장점

    • 양쪽에서 데이터를 자유롭게 조회 가능
    • 객체 지향적인 관계 표현
  • 단점

    • 관계를 관리할 때 코드가 복잡해질 수 있음
    • 양쪽 데이터 동기화가 필요

1:1(OneToOne)

  1. 단방향1:1
  • 한 엔티티가 다른 엔티티와 1:1 관계를 가지는 경우
@Entity
public class User {
    @Id @GeneratedValue
    private Long id;

    @OneToOne
    @JoinColumn(name = "profile_id") // User 테이블에 FK 생성
    private Profile profile;
}

@Entity
public class Profile {
    @Id @GeneratedValue
    private Long id;
}

User 엔티티가 Profile을 참조하며, 외래 키는 User 테이블에 생성

  • 장점 : 단순하고 사용하기 쉬움
  • 단점 : 반대 방향(Profile -> User)에서 데이터를 조회할 수 없음

  1. 양방향1:1
  • 서로 참조가 필요한 경우
@Entity
public class User {
    @Id @GeneratedValue
    private Long id;

    @OneToOne(mappedBy = "user")
    private Profile profile;
}

@Entity
public class Profile {
    @Id @GeneratedValue
    private Long id;

    @OneToOne
    @JoinColumn(name = "user_id") // Profile 테이블에 FK 생성
    private User user;
}

mappedBy를 사용해 관계의 주인을 Profile로 설정

  • 장점 : 양쪽에서 데이터를 자유롭게 조회 가능
  • 단점 : 단방향에 비해 코드가 조금 더 복잡
    • 어느 테이블에 외래 키를 넣을 지 설계 시 고민이 필요

N:M(ManyToMany)

  1. 단방향 N:M
  • 다대다 관계를 단방향으로 관리
@Entity
public class Student {
    @Id @GeneratedValue
    private Long id;

    @ManyToMany
    @JoinTable(name = "student_class", 
               joinColumns = @JoinColumn(name = "student_id"),
               inverseJoinColumns = @JoinColumn(name = "class_id"))
    private List<Class> classes = new ArrayList<>();
}

@Entity
public class Class {
    @Id @GeneratedValue
    private Long id;
}

@JoinTable을 사용해 중간 테이블(student_class)을 생성

  • 장점 : 단순하고 구현이 쉬움
  • 단점 : 반대 방향에서 데이터 조회 불가

  1. 중간 엔티티를 사용한 N:M
  • 실무에서는 다대다 관계를 직접 매핑하기보다는 중간 테이블을 엔티티로 분리해 관리
@Entity
public class Student {
    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "student")
    private List<Enrollment> enrollments = new ArrayList<>();
}

@Entity
public class Class {
    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToMany(mappedBy = "clazz")
    private List<Enrollment> enrollments = new ArrayList<>();
}

@Entity
public class Enrollment {
    @Id @GeneratedValue
    private Long id;

    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;

    @ManyToOne
    @JoinColumn(name = "class_id")
    private Class clazz;

    private LocalDateTime enrolledAt; // 등록 일자
    private String status; // 상태 (예: "진행 중", "완료")
}
  • 추가 정보 저장 가능
    • Enrollment에 등록 날짜, 상태 등 관계에 대한 부가 정보를 저장할 수 있음
  • 유연한 관계 관리
    • 중간 엔티티를 통해 쿼리 작성이 명확하고 효율적
    • 확장성 있는 설계로 새로운 요구사항에도 쉽게 대응 가능

결론적으로,
기본적인 N:M 매핑은 간단하지만 실무에서는 중간 엔티티를 활용한 방식이 훨씬 유리하다.
설계 초기 단계에서 확장성과 유지보수성을 고려해 중간 엔티티를 사용하는 것이 좋다.

0개의 댓글