티스토리 뷰

Spring

[Spring] JPA 연관관계 매핑

Gray__ 2022. 5. 9. 16:38

 

객체와 테이블 연관관계 차이를 이해하고, 객체의 참조와 테이블의 외래키를 매핑할 수 있어야 합니다.

객체를 테이블에 맞춰 데이터 중심으로 모델링하면 협력관계를 만들 수 없습니다. 테이블은 반드시 외래키로 조인을 해서 연관된 테이블을 찾고, 객체는 참조를 사용해서 연관된 객체를 찾습니다 ex) member.getTeam(). 따라서 테이블과 객체 사이에는 이런 큰 간격이 존재하게 됩니다.

 

단방향 연관관계

연관관계가 없는 객체

테이블의 연관관계는 외래 키 하나로 양방향이 존재합니다. 즉 테이블의 연관관계는 양방향이라는 것이 없다고 할 수 있습니다. 왜냐하면 외래키 하나만 있으면 양쪽 테이블에 관해 알 수 있기 때문입니다.  MEMBER.TEAM_ID 외래 키 하나로 연관관계를 가지고 양쪽 조인이 가능합니다.

SELECT *
FROM MEMBER M
JOIN TEAM T on M.TEAM_ID = T.TEAM_ID

SELECT *
FROM TEAM T
JOIN MEMBER M on T.TEAM_ID = M.TEAM_ID

 

문제는 객체입니다. 객체를 테이블에 맞춰 데이터 중심으로 모델링하면 협력 관계를 만들 수 없습니다. Member -> Team으로 단방향 관계가 존재한다고 하면 Team이 Member에 관하여 알고 싶을 때는 알 방법이 없기 때문에 Team에도 Member를 가질 수 있는 리스트가 있어야합니다.

 

 

양방향 연관관계, 연관관계 주인과 mappedBy

양방향 객체 연관관계

객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개입니다. 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 합니다. 

class A(){
	B b;
}

class B(){
	A a;
}

// A -> B: a.getB()
// B -> A: b.getA()

만약 내가 새로운 팀에 들어가고 싶으면 Member에 있는 team 객체를 수정해야 할까 아니면 Team에 있는 Member List를 수정해야 할까? 라는 궁금증이 생깁니다. 데이터베이스 입장에서는 외래 키 값만 업데이트 되면 됩니다. 즉, 둘 중 하나로 외래키를 관리해야 합니다.

이 때  외래키를 관리하는 객체의 멤버를 연관관계 주인(Owner)이라고 합니다.

 

연관관계의 주인의 몇 가지 속성이 있습니다

1. 객체의 두 관계중 하나를 연관관계의 주인으로 지정합니다.
2. 연관관계의 주인만이 외래키를 관리(등록, 수정)할 수 있습니다.
3. 주인이 아닌 쪽은 읽기만 가능합니다.
4. 주인은 mappedBy 속성을 사용하지 않습니다.
5. 주인이 아니면 mappedBy 속성으로 주인을 지정합니다.

 

그러면 누구를 주인으로 지정해야 할까?

-> 외래 키가 있는 곳을 주인으로 지정해주면 됩니다.

위 예제에서는 Member.team이 연관관계의 주인이고, 1:N 관계에서는 N이 연관관계의 주인입니다.

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

    @Column(name = "USERNAME")
    private String name; 

    private int age;
	
    // 연관관계의 주인 !!
    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

//-------------------------------------------------------------//

@Entity
public class Team {

    @Id @GeneratedValue 
    private Long id;

    private String name;

    // 주인이 아니기 때문에 mappedBy로 매핑
    @OneToMany(mappedBy = "team")
    List<Member> members = new ArrayList<Member>();
}

 

양방향 매핑 시 가장 많이 하는 실수

  • 연관관계의 주인에 값(mappedBy)을 입력하지 않음 -> 역방향으로 설정하기 때문에 값 쓰이지 X
  • 양방향 매핑 시에는 양쪽에 값을 다 세팅하는게 좋다
  • 양방향 매핑 시 무한 루프를 조심 -> toString(), lombok, JSON 생성 라이브러리
  • 컨트롤러에서는 entity를 반환 X. 엔티티는 dto로 변환해서 반환.
댓글