- 연관관계가 필요한 이유?
- 객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다.
- 객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없다.
-테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
-객체는 참조를 사용해서 연관된 객체를 찾는다.
-테이블과 객체 사이에는 이런 큰 간격이 있다.
단방향 연관관계
위의 연관관계와 같이 Member는 Teamid의 객체를 가지고 있다.(객체 참조)
MEMBER 테이블은 TEAM_ID를 FK로 가지고 있다. (N:1)
@Entity
public class Member {
@Id
@GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
위의 코드와 같이 객체지향적 설계를 하려면 테이블 설계의 관점이 아닌 객체의 관점으로 설계를 해야 한다. Member는 하나의 팀만 소속할 수 있으며, 반대로 Team은 여러 회원을 소속할 수 있어서 Member는 N이 되고 Team은 1이 되어서 N:1 관계가 된다. 그래서 Team의 객체를 참조하며, @ManyToOne어노테이션으로 테이블에 대한 외래 키를 지정해 주고 객체와 테이블의 연관관계를 매핑하기 위해 @JoinColumn 어노테이션을 사용하면 된다.
양방향 연관관계
위의 코드에선 Member에서 Team으로 객체를 참조할 수 있지만, Team에서 Member로 가지는 못한다. 하지만 테이블에서는 이미 Member에서 Team의 외래 키를 가지고 있고, Team은 Team의 기본키와 Member의 외래 키로 서로 바라보고 있다.
객체 연관관계는 Member와 Team을 서로 연관관계로 맺어주려면 서로 객체를 참조해야 하나, 테이블에서는 외래 키 하나로 양방향 연관관계를 다 가지고 있다.
위의 코드와 같이 Team클래스에서 Member를 참조하는 List객체를 만들어주었다. ArrayList는 관례상 nullpointException이 뜨지 않도록 덮어주는 용도로 사용한다.
@OneToMany(mppedby = "team")으로 설정하였는데, 이 mappedBy의 name은 연관관계로 지정한 @ManyToOne의 객체의 이름을 사용하면 서로 연관관계 매핑이 된다. 이 말에는 모순이 있는데, 객체에서의 양방향 연관관계는 존재하지 않는다. 하지만 단방향 연관관계를 서로 지정하여 양방향 연관관계로 보이는 것이다.
여기서 중요한 점은 "객체와 테이블이 관계를 맺는 차이" 이다.
- 객체 연관관계 = 2개
회원 - > 팀 연관관계 1개(단방향)
팀 -> 회원 연관관계 1개(단방향)
- 테이블 연관관계 = 1개
회원 <-> 팀의 연관관계 1개(양방향)
연관관계의 주인
- 양방향 매핑 규칙
- 객체의 두 관계 중 하나를 연관관계의 주인으로 지정
- 연관관계의 주인만이 외래 키를 관리(등록, 수정)
- 주인이 아닌 쪽은 읽기만 가능
- 주인은 mappedBy 속성 사용 x
-주인이 아니면 mappedBy 속성으로 주인 지정
- 주인으로 정하는 기준은?
- 외래 키가 있는 곳을 주인으로 정한다. (1:N 관계에서 N이 되는 쪽을 주인으로 지정한다.)
- 위의 코드에서는 Member.team이 연관관계의 주인이 된다.
위의 결과를 보면 TEAM_ID = null이 나오게 된다. 그 이유는 team.getMembers().add(member); 때문이다. members 객체는 주인이 아닌 읽기 전용으로 매핑이 되었는데 getMembers.add로 값을 넣어주었기 때문에 null이 나오게 된다.
위의 코드를 아래 코드와 같이 바꿔주었다.
위의 코드와 같이 team.getMember()가 아닌 연관관계의 주인인 member.setTeam으로 값을 넣어주었더니 정상적으로 TEAM_ID의 값이 정상적으로 들어간 모습이다.
양방향 연관관계 주의점
- 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하는 게 좋다.
- 연관관계 편의 메소드를 생성하자
- 양방향 매핑 시에 무한루프를 조심
위의 코드와 같이 연관관계 주인인 Member.setTeam으로 값을 넣어줄 때 Team의 getMembers도 같이 값을 넣어준다.
출처 : https://www.inflearn.com/course/ORM-JPA-Basic#
'JPA' 카테고리의 다른 글
고급 매핑 (0) | 2021.10.10 |
---|---|
다양한 연관관계 매핑 (0) | 2021.10.09 |
엔티티 매핑 (0) | 2021.10.07 |
flush, 준영속 상태 (0) | 2021.10.06 |
영속성 컨텍스트, 1차캐시, 변경감지 (0) | 2021.10.05 |