카테고리 없음

[자바 ORM 표준 JPA 프로그래밍] 5장

lim.dev 2023. 4. 25. 21:07

연관관계 매핑 기초

이번 장의 목표는 객체의 참조와 테이블의 외래 키를 매핑하는 것이었습니다!

객체 관계 매핑에서 가장 어려운 부분이 바로 객체 연관관계와 테이블 연관관계를 매핑하는 것이라고 합니다.

 

단방향  연관관계

N:1

객체 연관관계에서는 단방향 관계로 존재하지만, 테이블 상에서는 양방향 관계입니다. 

만약 팀과 멤버 테이블이 있을 때 객체에서는 member.getTeam()으로 가능하지만 Team에서 member로 접근하는 필드는 없습니다. 하지만 테이블 연관관계의 경우 MEMBER 테이블의 TEAM_ID 외래키로 MEMBER JOIN TEAM과 TEAM JOIN MEMBER가 가능합니다.

 

  • 객체는 참조(주소)로 연관관계를 맺는다.
  • 테이블은 외래키로 연관관계를 맺는다.

 

Team findTeam = member1.getTeaam();

객체는 이런식으로 참조를 사용해서 연관관계를 탐색할 수 있는데 이것을 객체 그래프 탐색이라고 합니다.

 

SELECT T.*
FROM MEMBER M
	JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
WHERE M.MEMBER_ID = 'member1'

데이터베이스(테이블)의 경우 이처럼 외래 키를 사용해서 조인을 하여 연관관계를 탐색할 수 있습니다.

 

@ManyToOne: 다대일 관계의 매핑 정보입니다. 

@JoinColumn(name="외래키"): 조인 컬럼은 외래키를 매핑할 때 사용합니다. name 속성에는 매핑할 외래 키 이름을 지정합니다. 이 어노테이션은 생략할 수 있습니다.

@ManyToOne: 다대일 관계에서 사용합니다.

연관관계 사용

저장

  • JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 합니다.

 

조회

연관관계가 있는 엔티티를 조회하는 방법은 2가지입니다.

  • 객체 그래프 탐색: 객체 연관관계를 사용한 조회
  • 객체지향 쿼리 사용: JPQL

JPQL 조인 검색 예시

더보기
String jpql = "select m from Member m join m.team t where" + "t.name=:teamName"

List<Member> resultList = em.CreateQuery(jpql, Member.class)
										.setParameter("testName", "팀 1")
                                        .getResultList();

 

수정

수정은 em.update() 같은 메소드가 없습니다. 단순히 불러온 엔티티의 값만 변경해두면 트랜잭션을 커밋할 때 플러시가 일어나면서 변경 감지 기능이 작동합니다. 변경사항은 데이터베이스에 자동으로 반영하며 이는 연관관계 수정시에도 같습니다.

 

제거

member.setTeam(null);

위와 같이 연관관계를 null로 설정하면 됩니다. 연관된 엔티티를 삭제할 경우 기존의 연관 관계를 먼저 제거하고 삭제해야 합니다.

member1.setTeam(null);
member2.setTeam(null);
em.remove(team);

 

양방향 연관관계

1:N

@OneToMany(mappedBy="team")
private List<Member> members = new ArrayList<Member>();

mappedby는 왜 필요할까요? 객체에는 양방향 연관관계라는 것이 없어서 서로 다른 단방향 연관관계 2개를 애플리케이션 로직으로 잘 묶어서 양방형처럼 보이게 합니다. 따라서 엔티티를 양방향 연관관계로 사용하면 객체의 참조는 둘인데 외래 키는 하나라서 둘 사이의 차이가 발생하게 됩니다. mappedby는 이 경우에 둘 중 어떤 관계를 사용할지, 연관관계의 주인을 정해주는 것이다.

 

  • 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야 하는 데 이를 연관관계의 주인 이라 합니다.
  • 연관관계의 주인만이 데이터베이스 연관관계와 매핑되며, 외래키를 관리 할 수 있습니다.
  • 주인이 아니면 읽기만 할 수 있습니다.
  • 주인은 mappedBy 속성을 사용하지 않습니다.
  • 주인이 아니면 mappedBy 속성을 이용하여 연관관계의 주인을 지정해줍니다.

연관관계의 주인을 정한다는 것은 외래 키 관리자를 선택하는 것입니다.

연관관계의 주인은 외래 키가 있는 곳으로 정합니다.

 

양방향 연관관계의 주의점

주인이 아닌 곳에만 값을 설정한 경우 외래키에 null 값이 입력된다. 왜냐하면 연관관계의 주인만이 외래 키의 값을 변경할 수 있기 때문입니다.

사실 객체 관점에서 양쪽 방향에 모두 같은 값을 입력해주는 것이 가장 안전하다. JPA를 사용하지 않는 순수 객체 상태에서는 심각한 문제가 발생할 수 있습니다.

member.setTeam(team1);
team1.getMembers().add(member1)

그러므로 위와 같이 객체의 양방향 연관관계는 양쪽 모두 관계를 맺어주어야 합니다.

 

정리

단방향과 비교했을 때 양방향의 장점은 반대방향으로 객체 그래프 탐색 기능이 추가된 것 뿐입니다.