본문 바로가기
Java/ORM

JAVA ORM - JPA(연관관계 매핑)

by 티코딩 2024. 8. 1.

연관관계?

항상 ERD를 보면 테이블간 관계가 복잡하게 얽혀있다. 그래서 이 연관관계 매핑을 능숙하게 할 줄 알아야 한다.

모든 연관관계에는 주인테이블이 있고 비주인테이블이 있게된다. 주인테이블은 외래키를 실제로 관리하는 엔티티가 맡게 된다.

연관관계의 종류를 알아보자.

 

1:1관계

예를 들어 Member 테이블과 MemberDetail 테이블이 있다고하면, 한명의 회원은 한개의 회원 상세 정보를 가진다.

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @OneToOne
    @JoinColumn(name = "member_detail_id")
    private MemberDetail memberDetail;
}

@Entity
public class MemberDetail {
    @Id @GeneratedValue
    private Long id;
    private String address;
}

일대일 관계일땐 한쪽에만 @OneToOne 컬럼을 작성해준다.

 

1:N관계

예를 들어보면 Team테이블, Member테이블이있다고치면, 한 팀에는 여러명의 회원을 가질 수 있다.

@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
}

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
}

1이 되는 엔티티에 @OneToMany, N이 되는 테이블에 @ManyToOne, @JoinColumn을 붙혀준다.

@JoinColumn은 항상 주인이되는 테이블에 붙는다.

 

M:1 관계

예를들면 Order테이블, Customer테이블이 있는데, 여러개의 주문은 하나의 고객에 종속된다.

@Entity
public class Order {
    @Id @GeneratedValue
    private Long id;
    private String orderNumber;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    private Customer customer;
}

@Entity
public class Customer {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @OneToMany(mappedBy = "customer")
    private List<Order> orders = new ArrayList<>();
}

 

 

 

M:N 관계

Student 테이블, Course 테이블이 있을 때, 학생과 강의의 관계는 다대다 관계가 된다. 다대다 관계는 중간 테이블을 사용해 매핑된다.

@Entity
public class Student {
    @Id @GeneratedValue
    private Long id;
    private String name;

    @ManyToMany
    @JoinTable(name = "student_course",
            joinColumns = @JoinColumn(name = "student_id"),
            inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses = new ArrayList<>();
}

@Entity
public class Course {
    @Id @GeneratedValue
    private Long id;
    private String title;

    @ManyToMany(mappedBy = "courses")
    private List<Student> students = new ArrayList<>();
}

 

 

누가 주인인가?

위에서 주인테이블은 외래키를 실제로 관리하는 엔티티가 맡게 된다고 했다.

테이블 연관관계는 단방향, 양방향이 있다.

Member테이블이 있고, Team 테이블이 있다고할 때,

멤버에서 내가 소속된 팀을 알고싶으면 Member의 팀아이디로 조인하면 알 수 있다.

팀에서 소속된 멤버를 알고싶으면 나의 PK랑 멤버의 FK랑 조인하면 알 수 있다.

 

사실 테이블에 연관관계에는 방향이라는 개념이 없다. 하지만 객체는 어떨까?

아래 테이블처럼 되어있을땐, 멤버에서 팀은 조회가되지만, 팀에서 멤버는 조회할 수 없다.

Member
id
Team team
username

 

Team
id
name

 

그렇다면 아래처럼 객체가 세팅되어있으면 양방향 통신이 가능하다.

Member
id
Team team
username

 

Team
id
name
List members

 

 

mappedBy

객체의 연관관계

Member -> Team

Member <- Team

이렇게 단방향 연관관계를 두개 맺는다.

 

테이블의 연관관계

Member - Team

PK 와 FK를 조인만해도 양쪽을 다 알 수 있다.

 

이런 양방향 매핑에서 외래키를 업데이트할때 양쪽다 업데이트해야할지 한쪽만할지 이런 딜레마가 생기는데,

이래서 한쪽만 외래키를 관리해야한다. 이때 필요한게 주인(Owner)이다.

연관관계의 주인만 외래키를 관리할수있고, 비주인은 읽기만 가능하다.

그리고 비주인은 mappedBy 속성으로 주인을 지정해 줘야한다.

Team 엔티티에 mappedBy = "team" 을 보면 Member 엔티티의 team필드가 연관관계의 주인이라는 것.

다시 정리하면 연관관계의 주인은 외래키의 위치를 기준으로 정한다.