목표
- 객체와 테이블 연관관계의 차이를 이해
- 객체의 참조와 테이블의 외래 키를 매핑
객체와 테이블 연관관계의 차이를 이해
객체를 테이블에 맞추어 모델링 했을 때 문제점 (참조 대신에 외래 키를 그대로 사용)
협력 관계를 만들 수 없다.
테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾기 때문에 아래와 같이 번거로운 코드가 발생된다.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setUsername("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);
객체의 참조와 테이블의 외래 키를 매핑
단반향 연관관계
객체 지향 모델링 (객체 연관관계 사용)
아래와 같이 Member에서 Team을 바로 불러올 수 있다.
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
member.setTeam(team);
em.persist(member);
Member findMember = em.find(Member.class, member.getId());
Team findTeam = findMember.getTeam();
tx.commit();
양반향 연관관계와 연관관계의 주인
양쪽에서 참조해서 볼 수 있게 연관관계를 맺는것
테이블 관계는 변함이 없다 테이블은 외래 키로 조인을 사용해서 서로를 조회할 수 있다. (방향이 없다)
Team 클래스에 아래와 같이 연관관계를 매핑해주었다. mappedBy 에서 사용한 team은 연관관계가 맺어있는 Member 클래스에서 @ManyToOne을 걸어준 변수의 이름을 넣어서 JPA에게 알려준다.
@OneToMany(mappedBy = "team")
private List<Member> memberList = new ArrayList<>();
Member findMember = em.find(Member.class, member.getId());
List<Member> memberList = findMember.getTeam().getMemberList();
for(Member mem : memberList){
System.out.println(mem.getUsername());
}
위의 코드를 보면 findMember.getTeam 을 찾아 해당 Team에 MemberList를 조회한다. 이처럼 서로의 정보를 조회할 수 있는 것이 양반향 연관관계 이다.
연관관계와 주인과 mappedBy
객체의 양방향 관계는 서로 다른 단방향 관계 2개이다. -> 개체를 양방향으로 참조하려면 단뱡향 연관관계를 2개 만들어야 한다.
테이블은 외래 키 하나로 두 테이블의 연관관계를 관리한다. (키 하나로 양쪽 조인)
양방향 매핑 규칙
- 객체의 두 관계중 하나를 연관관계의 주인으로 지정
- 연관관계의 주인만이 외래 키를 관리( 등록, 수정 )
- 주인이 아닌쪽은 읽기만 가능 하고 mappedBy 속성을 사용하여 주인을 지정해야 한다.
그렇다면 누구를 주인으로 정해야 할까?
외래 키가 있는 곳을 주인으로 정해라!
Member - Team 이 있다면 다 인 Member를 주인으로 한다.
Team은 읽기만 가능한 가짜 매핑이다.
비지니스 로직을 기준으로 주인을 선택하면 안된다. [다] 쪽에 주인을 걸어주는게 좋다.
양방향 매핑시 가장 많이 하는 실수
-> 연관관계의 주인에 값을 입력하지 않음
예를들어 team.getMembers().add(member) 로 주인이 아닌 곳에만 값을 넣어주면
아래와 같이 Member테이블에 TEAM_ID 가 매핑되지 않는다.
Team team = new Team();
team.setName("TeamA");
em.persist(team);
Member member = new Member();
member.setName("aejeong");
team.getMembers().add(member);
// 연관관계의 주인에 값을 설정해주어야 한다.
member.setTeam(team);
em.persist(member);
하지만 순수 객체 관계를 고려하면 항상 양쪽다 값을 입력해야 한다.
아니면 연관관계 편의 메소드를 생성한다.
어디서 넣든 상관없다. 한쪽에서만 해주는게 좋다 양쪽에서 해주면 무한루프의 위험이 있다.
private List<Member> members = new ArrayList<>();
public void addMember(Member member){
member.setSteam(this);
member.add(member);
}
toString(), lombok, JSON 생성라이브러리 를 사용시 무한루프를 조심하자.
단반향 매핑만으로도 이미 연관관계 매핑은 완료된것이다.
처음 설계할 때 우선 단반향관계로 한다. 양방향은 반대 방향으로 조회 기능이 추가된 것 뿐이다.
JPQL에서 역방향으로 탐색할 일이 많아서 필요할 때 추가해도 된다. 테이블에 영향을 주지 않기 때문!
'WEB > JPA' 카테고리의 다른 글
6. 자바 ORM 표준 JPA 프로그래밍 - 고급매핑 (0) | 2021.05.17 |
---|---|
5. 자바 ORM 표준 JPA 프로그래밍 - 다양한 연관관계 매핑 (0) | 2021.05.14 |
3. 자바 ORM 표준 JPA 프로그래밍 - 엔티티 매핑 (0) | 2021.05.13 |
2. 자바 ORM 표준 JPA 프로그래밍 - 내부 동작 방식 (0) | 2021.05.13 |
1. 자바 ORM 표준 JPA 프로그래밍 - 간단한 실습 (0) | 2021.05.13 |