- 방향: [단방향, 양방향]이 있다.
회원과 팀 관계가 있을 때 회원 → 팀 또는 팀 → 회원 둘 중 한 쪽만 참조하는 것을 단방향,
양쪽 모두 서로 참조하는 것을 양방향 관계라 함. 방향은 객체관계에만 존재함- 다중성: [다대일 N:1, 일대다 1:N, 일대일 1:1, 다대다 N:M] 다중성이 있음
회원과 팀 관계에서 여러 회원은 한 팀에 속하므로 회원과 팀은 다대일 관계이고,
반대로 한 팀에 여러 회원이 소속될 수 있으므로 팀과 회원은 일대다 관계임- 연관관계의 주인: 객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 함
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@Column(name = "TEAM_ID")
private Long teamId;
…
}
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
…
}
참조 대신에 외래 키를 그대로 사용함
//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeamId(team.getId());
em.persist(member);
외래키 식별자를 직접 다룸
//조회
Member findMember = em.find(Member.class, member.getId());
//연관관계가 없음
Team findTeam = em.find(Team.class, team.getId());
식별자로 다시 조회
위는 객체 지향적인 방법이 아님
즉, 객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없음

@Entity
public class Member {
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
private int age;
// @Column(name = "TEAM_ID")
// private Long teamId;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
…
}
//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);
//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team); //단방향 연관관계 설정, 참조 저장
em.persist(member);
//조회
Member findMember = em.find(Member.class, member.getId());
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();

(Member 엔티티 코드는 단방향과 동일)
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
List<Member> members = new ArrayList<Member>();
…
}
//조회
Team findTeam = em.find(Team.class, team.getId());
int memberSize = findTeam.getMembers().size(); //역방향 조회
객체와 테이블 간에 연관관계를 맺는 차이를 이해해보자
객체의 양방향 연관관계
테이블의 양방향 연관관계
두 객체 중 하나로 외래 키를 관리해야 함!
양방향 매핑 규칙
mappedBy 속성 사용 XmappedBy 속성으로 주인 지정 (어떤 컬럼에 의해 매핑되었음을 표시)누구를 주인으로?
외래 키가 있는 곳을 주인으로 정하자 (외래키가 있는 곳이 항상 N이 됨, N 쪽이 연관 관계의 주인)
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
//역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
team.getMembers().add(member);
//연관관계의 주인에 값 설정
member.setTeam(team); //**
em.persist(member);
team.getMembers().add(member)를 입력하지 않아도team.getMembers()로 값을 조회하면 JPA는 정상적으로 값을 가져온다. 그러나 em.flush(), em.clear() 등으로 영속성 컨텍스트를 정리하지 않은 상태에서는 1차 캐시에 들어있는 엔티티를 가져오므로team.getMembers().add(member)를 입력하지 않았을 경우team.getMembers()로 값을 조회하면 아무 것도 조회되지 않는다.
순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자
연관관계 편의 메소드를 생성하자
public void changeTeam(Team team) { // 로직이 섞여있을 경우 Getter, Setter 사용을 피하자.
this.team = team;
team.getMembers().add(this);
}
// or
public void addMember(Member member) {
member.setTeam(this);
members.add(member);
}
양방향 매핑시에 무한 루프를 조심하자
team.getMembers().toString -> member.getTeam().toString() -> Loop...)