-
JPA - 연관관계 매핑Spring/JPA 2022. 3. 8. 18:10728x90반응형
연관관계 매핑
객체를 테이블에 맞추어 모델링하면 연관관계를 만들 수 없지만 테이블은 외래 키로 조인을 사용하여 연관된 테이블을 찾을 수 있다. 이런 차이 때문에 객체를 테이블에 맞춘 모델링은 좋은 방법이 아니다.
@Entity public class Member { @Id @GeneratedValue private Long id; @Column(name = "USERNAME") private String name; @Column(name = "TEAM_ID") private Long teamId; … } @Entity public class Team { @Id @GeneratedValue private Long id; private String name; … }
위와 같이 테이블에 맞춘 모델링은 외래 키 식별자를 직접 다룰 수밖에 없다. 때문에 MEMBER 테이블에서 가져온 member 객체에서 Team의 정보를 알기 위해서는 다시 TEAM 테이블에서 정보를 가져와야 한다.
//조회 Member findMember = em.find(Member.class, member.getId()); //연관관계가 없음 Team findTeam = em.find(Team.class, team.getId());
이러한 방식은 불편함만 있을 뿐만 아니라 성능에서도 문제가 된다. JPA에서는 이러한 문제점들을 해결하기 위해 내부적으로 객체지향 모델링을 제공한다.
단방향 연관관계
@Entity public class Member { @Id @GeneratedValue private Long id; @Column(name = "USERNAME") private String name; private int age; // @Column(name = "TEAM_ID") // private Long teamId; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; … }
위와 같이 연관관계 설정 @ManyToOne을 해주게 되면 객체 그래프 탐색이 가능해지기 때문에 조회, 수정이 객체지향적으로 처리할 수 있게 된다.
//조회 Member findMember = em.find(Member.class, member.getId()); //참조를 사용해서 연관관계 조회 Team findTeam = findMember.getTeam(); // 새로운 팀B Team teamB = new Team(); teamB.setName("TeamB"); em.persist(teamB); // 회원1에 새로운 팀B 설정 member.setTeam(teamB);
양방향 연관관계
단방향 매핑은 Member 엔티티에 @ManyToOne의 연관관계만 설정했지만 양방향 매핑은 Team 엔티티에 @OneToMany 설정까지 해주는 방법이다. 단방향 매핑은 Member에서만 Team을 참조할 수 있었지만 양방향 매핑은 Team에서 Member로 참조도 할 수 있게 된다. 즉 양쪽 모두 서로를 참조할 수 있게 해 준다.
객체의 양방향 연관관계와 테이블의 연관관계 차이
- 객체의 양방향 관계는 사실 양방향 관계가 아니라 서로 다른 단방향 관계 2개이다.
- 즉, 객체를 양방향으로 참조하기 위해서는 단방향 연관관계를 2개 만들어야 한다.
- 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리할 수 있다.
양방향 매핑 규칙
- 객체의 두 관계 중 하나를 연관관계의 주인으로 지정해야 한다.
- 연관관계의 주인만이 외래 키를 관리(등록, 수정)를 할 수 있다.
- 주인이 아닌 쪽은 읽기만 가능하다.
- 주인은 mappedBy 속성 사용 X
- 주인이 아니면 mappedBy 속성으로 주인 지정한다.
- 외래 키가 있는 곳이 주인이다.
- 연관관계의 주인에게 값을 입력해야 한다.
- 단방향 매핑을 잘하고 양방향은 필요할 때 추가해도 된다.
@Entity public class Member { @Id @GeneratedValue private Long id; @Column(name = "USERNAME") private String name; private int age; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; … } @Entity public class Team { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "team") List<Member> members = new ArrayList<Member>(); … }
주의 사항
- 연관관계 주인에 값을 입력해야 한다
- 아래와 같이 주인이 아닌 곳에 값을 입력하면 값이 DB에 값이 안 들어간 것을 볼 수 있다.
Team team = new Team(); team.setName("TeamA"); em.persist(team); Member member = new Member(); member.setName("member1"); //주인이 아닌 곳에 데이터를 넣어도 DB에는 저장이 안된다. team.getMembers().add(member); em.persist(member);
- 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하는 것이 좋다
- 연관관계 편의 메서드를 이용하여 양쪽에 값을 설정
public void addOrderItem(OrderItem orderItem) { orderItems.add(orderItem); orderItem.setOrder(this); }
- 양방향 매핑 시에 무한 루프를 조심해야 한다.
ex) toString 오버 라이딩 시 발생
참고
단방향 매핑만으로도 이미 연관관계 매핑은 완료된 상태이다.
양방향 매핑은 반대 방향으로 조회(객체 그래프 탐색) 기능이 추가된 것뿐이므로
단반향 매핑을 잘하고 양방향은 필요할 때 추가하는 것이 좋다
(추가 시 테이블에 영향을 주지 않기 때문)728x90반응형'Spring > JPA' 카테고리의 다른 글
JPA - 상속관계 매핑 (0) 2022.03.09 JPA - 다양한 연관관계 매핑(다대일, 일대다, 일대일, 다대다) (0) 2022.03.09 JPA - 엔티티 매핑 (0) 2022.03.08 JPA - 영속성 컨텍스트 (0) 2022.03.07 JPA - JPA의 내부 동작과 Entity의 생명주기 (0) 2022.03.07