김영한님의 '자바 ORM 표준 JPA 프로그래밍'을 읽고 정리한 글입니다.
회원과 팀의 관계를 통해 이해해야한다
단방향
이므로 team-> member는 얻을 수 없다.양방향
관계이다.JPA를 사용하여 위 둘을 매핑해보자.
@Entity
public class Member {
...
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
여기서 @JoinColumn
은 외래 키를 매핑할 때 사용한다. 생략이 가능하다.
만약 생략시 기본 전략을 이용한다.
필드명 + _ + 참조하는 테이블의 컬럼명
@ManyToOne 속성
반대로 팀에서 회원으로 접근하는 관계를 추가하자.
Team 엔티티
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
객체에는 양방향 연관관계라는 것이 없다.
서로 다른 단방향 연관간계를 묶은 것이다.
테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다.
엔티티를 단방향으로 매핑하면 참조를 하나만 사용한다.
하지만 양방향 매핑이면 객체의 참조는 둘 인데 외래 키 는 하나 이다.
-> JPA에서는 두 연관관계 중 하나를 정해 테이블의 외래키를 관리한다. 이를 연관관계의 주인
이라고 한다.
연관관계의 주인만이 외래 키를 관리(등록,수정,삭제)할 수 있다.
주인이 아닌 쪽은 읽기만 가능하다.
주인은 mappedBy 속성을 사용하지 않는다.
주인이아니면 mappedBy속성을 사용해 주인을 지정해야한다.
연관관계의 주인을 정하는 것은 외래키 관리자
를 정하는 것이다.
만약 Member.team을 주인으로 선택하면 자기 테이블에 있는 외래 키를 관리하면 된다.
하지만 Team.member를 선택하면 물리적으로 다른 테이블의 외래 키를 관리해야한다.
여기서는 회원 테이블이 외래 키를 갖고 있으므로 Member.team이 주인이 된다.
Team.members에는 (mappedBy="team")속성을 사용해야한다. 여기서team은 Member엔티티의 team 필드이다.
데이터 베이스의 다대일, 일대다 관계는 항상 `다`쪽이 외래 키를 가진다. 따라서
`다`쪽인 @ManyToOne은 항상 연관관계의 주인이므로 mappedBy를 설정할 수 없다.
저장 방식은 단방향 방식과 동일하다.
엔티티 매니저는 주인을 통해서 외래 키를 관리한다.
team1.getMembers().add(member1) // 무시된다.(연관관계의 주인이 아니기에!!)
team이 아닌 member 엔티티를 통해서 해야한다.
member1.setTeam(team1) //연관관계 설정
흔히 하는 실수는 연관관계의 주인에는 값을 입력하지 않고 주인이 아닌 곳에만 값을 입력하는 것이다.
//회원 1,2 를 저장 후
Team team1 = new Team("team1", "팀1");
//주인이 아닌 곳에만 연관관계 설정
team1.getMembers().add(member1);
team2.getMembers().add(member2);
em.persist(team1);
위에서 봤듯이 Member.team에는 null들어가게 된다.
그럼 주인에만 저장해도 될까? -> 객체 관점으로는 양쪽 방향 모두 값을 넣어주는 것이 안전하다.
JPA를 사용하지 않은 순수한 객체 코드에서는 null이 들어간다.
결론은 양방향 연관관계는 양쪽 모두 관계를 맺어주어야한다.
✔ 정리
좋은 글이네요. 공유해주셔서 감사합니다.