연관관계가 필요한 이유
객체 지향 설계 목표 => 자율적인 객체들의 협력 공동체를 만드는 것
예제 시나리오
1. 회원과 팀이 있다
2. 회원은 하나의 팀에만 소속된다
3. 회원과 팀은 다대일 관계이다
public class Member {
@Id @GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
@Column(name="USERNAME")
private String name;
@Column(name = "TEAM_ID")
private Long teamId;
❌ 참조 대신에 외래키를 직접 다룬다
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());
Long findTeamId = findMember.getTeamId();
Team findTeam = em.find(Team.class, findTeamId);
❌ 외래키 식별자를 직접 다루며, 식별자로 다시 조회
❌ 객체 지향적 방법이 아님
테이블은 외래키로 조인을 사용하여 연관된 테이블을 찾고 객체는 참조를 사용해서 연관된 객체를 찾는다는 큰 차이가 있음 (=패러다임의 불일치)
단방향 연관관계
public class Member {
@Id @GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
@Column(name="USERNAME")
private String name;
@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();
⭕️ 참조로 연관관계 조회 - 객체 그래프 탐색
양방향 연관관계와 연관관계의 주인 ✩✩중요✩✩
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long Id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
!! 주의 !!
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
//역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);
em.persist(member);
❌ 이렇게 하면 member 테이블의 team_id가 null로 들어감
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);
Team findTeam = em.find(Team.class, team.getId());
List<Member> findMember = findTeam.getMembers();
for (Member m : findMember) {
System.out.println("m:" + m.getName());
}
tx.commit();
❌ 이렇게 한쪽에만 값을 설정해줄 경우, find시 1차 캐시에서 값을 가져오기 때문에 findMember 리스트는 비어있게 된다. 저 경우 flush를 통해 디비에 값을 다 넣어주거나 연관관계 편의 메소드를 추가해줘야 한다.
public void setTeam(Team team) {
this.team = team;
team.getMembers().add(this);
}
⭕️ 어느 곳에 할지는 마음대로, 세팅할 때 역방향에도 자동 값 세팅하도록 메소드를 생성하면 좋다