단방향 관계를 매핑할 때 둘 중 어떤 것을 사용해야 할지는 반대편 관계에 달려 있다.
반대편이 일대다 관계면 다대일을 사용하고 반대편이 일대일 관계면 일대일을 사용하면 된다.
참고로 일대일 관계는 다음 장에서 설명한다.
연관관계 사용
조회
연관관계가 있는 엔티티를 조회하는 방법은 크게 2가지다.
객체 그래프 탐색(객체 연관관계를 사용한 조회)
Member member =em.find(Member.class,"member1");Team team =member.getTeam(); // 객체 그래프 탐색System.out.println("팀 이름 = "+team.getName());// 출력 결과 : 팀 이름 = 팀1
객체지향 쿼리 사용(JPQL)
privatestaticvoidqueryLogicJoin(EntityManager em) {String jpql ="select m from Member m join m.team t where "+" t. name=: teamName ";List<Member> resultList =em.createQuery(jpql,Member.class).setParameter ("teamName","팀 1");.getResultList();for (Member member : resultList) {System.out.printin("[query] member. username=,"+member.getUsername());}// 결과: [query] member.username = 회원1// 결과: [query] member.username = 회원2
수정
privatestaticvoidupdateRelation(EntityManager em) {//새로운 팀 2Team team2 =newTeam("team2","팀2");em.persist(team2); //회원 1 에 새로운 팀2 설정Member member =em.find(Member.class,"memberl");member.setTeam(team2);}
객체에는 양방향 연관관계라는 것이 없다. 서로 다른 단방향 연관관계 2개를 애플리케이션 로직으로 잘 묶어서 양방향인 것처럼 보이게 할 뿐이다.
엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나다. 따라서 둘 사이에 차이가 발생한다. 이런 차이로 인해 JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야 하는데 이것을 연관관계의 주인(OWNER)이라 한다.
연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있다. 반면에 주인이 아닌 쪽은 읽기만 할 수 있다.
연관관계의 주인을 정한다는 것은 사실 외래 키 관리자를 선택하는 것이다.
연관관계의 주인은 외래 키가 있는 곳
연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정해야 한다. 여기서는 회원 테이블이 외래 키를 가지고 있으므로 Member.team이 주인이 된다.
양방향 연관관계의 주의점
양방향 연관관계를 설정하고 가장 흔히 하는 실수는 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것이다. 데이터베이스에 외래 키값이 정상적으로 저장되지 않으면 이것부터 의심해보자.
publicvoidtestSaveNonOwner() {//회원1 저장Member member 1=newMember ("member 1","회원1");em.persist(member1);//회원2 저장Member member2 =newMember ("member2","회원2");em.persist(member2);Team teaml =newTeam("teaml","팀 1"); //주인이 아닌 곳만 연관관계 설정teaml.getMembers().add(member1);teaml.getMembers().add(member2);em.persist(teaml);}
이는 연관관계의 주인이 아닌 Team.members에만 값을 저장했기 때문이다. 예제 코드는 연관관계의 주인인 Member.team에 아무 값도 입력하지 않았다. 따라서 TEAM_ID 외래 키의 값도 null이 저장된다.
순수한 객체까지 고려한 양방향 연관관계
객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다. 양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않는 순수한 객체 상태에서 심각한 문제가 발생할 수 있다.
publicvoidtestORM_양방향 () {//팀1 저장 Team teaml =newTeam ("teaml","팀 1");em.persist(team1);Member member 1=newMember ("member 1","회원1"); //양방향 연관관계 설정member1.setTeam(teaml) ; //연관관계 설정 member 1 -> teamlteam1.getMembers().add(member1); //연관관계 설정 teaml -> member 1em.persist(member1);Member member2 =newMember ("meinber2","회원2"); //양방향 연관관계 설정member2.setTeam (teaml); //연관관계 설정 member2 -> teamlteam1.getMembers().add(member2); //연관관계 설정 teaml -> member2em.persist(member2);}
연관관계 편의 메소드
양방향 연관관계는 결국 양쪽 다 신경 써야 한다. 이전에는 member.setTeam(team)과 team.getMembers.add(member)를 각각 호출하다 보면 실수로 둘 중 하나만 호출해서 양방향이 깨질 수 있다. 양방향 관계에서 두 코드는 하나인 것처럼 사용하는 것이 안전하다.