반응형
이 포스팅에서 작성하는 내용은 자바 ORM 표준 JPA 프로그래밍 (김영한 지음) 에서 발췌하였습니다.
1. 연관관계가 필요한 이유
'객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것' - 조영호(객체지향의 사실과 오해)
- 객체 vs 테이블
- 테이블 : 외래 키를 이용해 조인함.
- 객체 : 참조를 이용함
2. 관계형 DB를 기준으로 엔티티를 설계한 경우
1) Member 객체와 Team 객체(Member는 하나의 팀에만 속할 수 있음)
@Entity
@Table(name="TEAM_TWO")
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
...
}
@Entity
@Table(name="MEMBER_TWO")
public class Member {
@Id @GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
// 외래키를 넣어서 사용하는 방식. 객체지향스럽지 않고 관계형 DB에 초점이 맞춰진 설계
@Column(name = "TEAM_ID")
private Long teamId;
...
}
2) Insert 예시
try{
Team team = new Team();
team.setName("TEAM_A");
em.persist(team);
Member member = new Member();
member.setName("홍길동");
// Team의 외래키를 직접 넣어주는 방식 (객체지향스럽지 못함)
//member.setTeamId(team.getId());
em.persist(member);
tx.commit();
} catch(Exception e){
...
}
...
3) 단방향 매핑
아래의 예시에서는 @ManyToOne 어노테이션과 @JoinColumn을 이용
1) Member 객체와 Team 객체(Member는 하나의 팀에만 속할 수 있음)
@Entity
@Table(name="TEAM_TWO")
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
...
}
@Entity
@Table(name="MEMBER_TWO")
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;
...
}
2) Insert 예시
try{
Team team = new Team();
team.setName("TEAM_A");
em.persist(team);
Member member = new Member();
member.setName("홍길동");
// 연관관계 어노테이션을 이용해서 간편하게 사용 가능
member.setTeam(team);
em.persist(member);
tx.commit();
} catch(Exception e){
...
}
...
4) 양방향 매핑
Team객체에서도 Member객체를 호출 할 수 있도록 설정 (따지고 보면 단방향을 Team에다가도 추가한 꼴임)
아래의 예시에서는 @OneToMany 어노테이션과 mappedBy 속성을 이용
1) Member 객체와 Team 객체(Member는 하나의 팀에만 속할 수 있음)
@Entity
@Table(name="TEAM_TWO")
public class Team {
@Id @GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
private String name;
// Team에는 많은 Member가 있기 때문에 OneToMany
// mappedBy로 매핑
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
...
}
@Entity
@Table(name="MEMBER_TWO")
public class Member {
@Id @GeneratedValue
@Column(name="MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String name;
// 외래키를 넣어서 사용하는 방식. 객체지향스럽지 않고 관계형 DB에 초점이 맞춰진 설계
/*
@Column(name = "TEAM_ID")
private Long teamId;
*/
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
...
}
2) Insert 이후, Team에 속한 Member 객체를 가져오기
* em.flush()와 em.clear()로 쿼리를 빨리 보내고 캐시를 지워서 쿼리에서 가져올 수 있도록 함
try{
Team team = new Team();
team.setName("TEAM_A");
em.persist(team);
Member member = new Member();
member.setName("홍길동");
// 연관관계 어노테이션을 이용해서 간편하게 사용 가능
member.setTeam(team);
// flush와 clear를 통해 미리 쿼리를 날리고 영속성 컨텍스트를 비움. (추후에 1차캐시에서 가져오는 것이 아닌 쿼리에서 가져오게 하기 위함)
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
List<Member> members = findMember.getTeam().getMembers();;
for(Member m : members){
System.out.println("member_name : " + m.getName());
}
tx.commit();
} catch(Exception e){
...
}
...
5) 연관관계의 주인과 mappedBy
- 연관관계의 주인
- 양방향 매핑 시 사용
- 객체의 두 관계중 하나를 연관관계의 주인으로 설정
- 연관관계의 주인만이 외래 키를 관리함(등록 / 수정)
- 주인이 아닌 쪽은 읽기만 가능
- 주인은 mappedBy 속성을 사용하지 않음
- 주인이 아니면 mappedBy 속성으로 주인이 누구인 지 지정
- 외래 키가 있는 객체를 주인으로 정하면 보다 간편함
6) 양방향 매핑 시, 자주 하는 실수 모음
- 연관관계의 주인인 객체는 값을 반드시 넣어줘야함.
- 하지만, 순수한 객체 관계를 고려한다면 양쪽에 다 넣어주는 것이 좋음.
- toString(), lombok, JSON 관련하여 생성할 때 무한 루프를 조심하자.
7) 양방향 매핑 정리
- 설계 시, 양방향 매핑은 추후에 하고, 단방향 매핑만으로 연관관계를 매핑하는 것이 좋다.
- 양방향 매핑 : 반대 방향으로 조회 기능이 추가된 것이라고만 보는 것이 좋다.
- JPQL에서 역방향으로 탐색할 일이 많음
- 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨(테이블에 영향 X)
반응형
'BE > JPA' 카테고리의 다른 글
[JPA] 11. 다양한 연관관계 매핑 (0) | 2022.04.18 |
---|---|
[JPA] 호환되는 버전 찾기 (0) | 2022.04.18 |
[JPA] 9. 기본키 매핑 (0) | 2022.04.17 |
[JPA] 8. 엔티티 매핑 (0) | 2022.04.13 |
[JPA] 7. 플러시 & 준영속상태 (0) | 2022.04.13 |