강의를 듣던 중 단방향/양방향 연관관계나 연관관계의 주인이라는 말이 자주 나오는데 잘 이해가 되지 않아 정리한다!
연관관계를 정의할 때, 생각해야 할 것 세 가지가 있다.
- 방향: 양방향 혹은 단방향
- 연관 관계의 주인
- 다중성: 다대일, 일대다, 일대일, 다대다
단방향과 양방향부터 정리해보자.
단방향은 객체 관계에서 한쪽만 참조하는 것이고, 양방향은 양쪽이 서로 참조하는 것을 의미한다.
비즈니스 로직에서 두 객체가 서로 참조할 일이 있는지 고민해보면 된다.
예를 들어, Team.getMember()가 필요하면 Team->Member를 참조하는 구조이고,
Member.getTeam()이 필요하면 Member->Team을 참조하는 구조일 것이다.
양 쪽 모두 필요하면 양방향 관계로 정의하면 되는 것이다.
테이블은 외래키 하나로 양방향 쿼리가 가능하므로, 방향이라는 개념이 없다.
그러나 객체는 참조용 필드를 가지고 있는 객체만이 연관된 객체를 조회할 수 있다.
멤버와 팀 관계를 생각해보자.
이 때 멤버가 다, 팀이 1인 관계이므로
멤버 테이블에 외래키가 존재할 것이다.
(무조건 다 쪽에 외래키 존재함)
(일대일 관계에서는 어디든지 외래키를 둘 수 있음)
앞서 말했듯 테이블에서는 fk를 통해 양방향으로 값을 사용할 수 있지만, 객체는 다르다.
객체 관점에서, Member에서 Team을 참조하는 것은 FK가 있기에 가능하지만 Team에서 Member를 참조하는 것은 불가능하다.
@Entity
public class Member{
@Id
@GeneratedValue
@Column(nam="MEMBER_ID") //생략하면 자동으로 만들어줌
private Long id;
private String name;
@ManyToOne
@JoinColumn(name="TEAM_ID") //연관관계 주인
private Team team;
}
@Entity
public class Team {
@Id
@GeneratedValue
@Column(nam="TEAM_ID")
private Long id;
private String name;
@OneToMany(mappedBy = "team")//주인x
List<Member> members = new ArrayList<>();
}
따라서 Team엔티티에 Member 리스트를 만들고, @OneToMany를 통해 반대편에 매핑된 필드를 지정한다.
이제 Team->Member 참조가 가능해졌다.
Member와 Team이 있을 때, 팀의 멤버 정보가 수정되면 Team에서 Member리스트를 불러와 수정해야 할까, 아니면 Member의 setTeam등의 메소드를 통해 수정해야 할까?
객체 패러다임에서는 양쪽 다 문제가 없지만, DB패러다임에서는 연관관계가 하나임을 보장할 필요가 있다. 즉 연관관계의 주인이 필요한 것이다.
연관관계의 주인만이 외래키를 관리(등록, 수정 등)할 수 있고, 주인이 아닌 쪽은 읽기만 가능하다.
여기서 주인은 @JoinColumn,
주인이 아닌 쪽은 mappedBy를 사용할 것이다.
Member가 외래키를 가지고 있다.
따라서 Member의 team을 연관관계의 주인으로 지정하고(@JoinColumn), Team의 memberList는 mappedBy을 사용한다.
이렇게 되면 members 등록, 수정이 불가능하고 조회만 가능하다.
OrderItem은 내가 주문한 상품이 어떤 상품인지를 알아야 하니까 Item을 참조하는 반면,
Item에서는 나를 주문한 주문내역이 뭐가 있는지 굳이 알 필요가 없으므로
OrderItem->Item 단방향으로 한다!