연관관계 매핑 기초

유동우·2023년 7월 29일
0
post-thumbnail

단방향 연관관계

객체를 테이블에 맞추어 모델링 하기

//조회
Member findMember = em.find(Member.class, member.getId());

//연관관계가 없음
Team findTeam = em.find(Team.class, team.getId());

객체를 테이블에 맞추어 데이터 중심으로 모델링을 하면 "협력관계"를 만들 수 없다

테이블 -> 외래키로 조인을 사용하여 연관된 테이블 찾음
객체 -> 참조를 사용하여 연관된 객체를 찾음

=> 객체와 테이블의 연관관계의 차이가 발생

@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;

em.persist(team)을 할 경우 영속성 컨텍스트에 team의 기본키가 세팅되어 있기 때문에, member.setTeam(team) 을 하면 자동으로 member에 teamId가 매핑됨

//팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);

//회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team); //단방향 연관관계 설정, 참조 저장
em.persist(member);

이제 참조를 사용하여 연관관계 조회가 가능하다

Member findMember em.find(MEMBER.class, member.getId());

Team findTeam = findMember.getTeam();

양방향 연관관계와 연관관계의 주인 1 - 기본

객체와 테이블간에 연관관계의 차이
-> 테이블은 외래키를 사용해 조인하면 양방향 모두 서로 값을 알 수 있기 때문에 방향이라는것이 정해져 있지 않다.
-> 이에 반해 객체는 필드에 선언을 해야 하기 때문에 방향성을 지닌다.

@Entity
public class Team {
	
    @Id @GeneratedValue
	private Long id;
	
    private String name;
	
    @OneToMany(mappedBy = "team") //방향의 반대편 사이드에는 "team"이 걸려있다.
	List<Member> members = new ArrayList<Member>();}

양방향 연관관계는 사실 단방향 연관관계 2개가 묶인것이다.

위와 같이 양쪽에서 관리하게 된다면, 충돌문제가 발생할 수 있기 때문에
둘 중 하나로 외래키를 관리해야 한다

=> 그래서 나온것이 "연관관계의 주인"

연관관계의 주인

  • 객체의 두 관계 중 하나를 주인으로 지정
  • 연관관계의 주인만이 외래키를 관리 (등록,수정) 할 수 있다
  • 주인은 mappedBy 속성 사용 X
  • 주인이 아닌 쪽은 mappedBy 속성을 사용하여 지정하고, 읽기만 가능하다.

그렇다면 어느쪽을 주인으로 설정할 것인가???

=> 외래키가 있는 곳을 주인으로 정하자

테이블 연관관계를 보면

1:N 관계에서 N 방향 테이블에 외래키를 갖고 있다.
따라서 객체또한 N쪽에 연관관계의 주인을 지정해줘야 한다.
(무조건 이렇게 해야 한다 ! 는 아니지만 경험상 이렇게 하면 쉽게 할 수 있다)

양방향 연관관계와 연관관계의 주인 2 - 주의점, 정리

양방향 매핑시 연관관계의 주인에 값을 입력해야 한다

Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("member1");

//역방향(주인이 아닌 방향)만 연관관계 설정
team.getMembers().add(member);

//연관관계의 주인에 값 설정
member.setTeam(team); //**

em.persist(member);
  • 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하자
  • 연관관계 편의 메서드를 생성하자
  • 무한 루프에 빠지는 것을 조심하자
    (toString(), lombok, JSON 생성 라이브러리)

중요한것은 단방향 매핑만으로도 이미 연관관계 매핑이 완료되어야 된다.
(양방향은 단순히 그래프 탐색 기능을 추가해 준 것뿐이다)

편의 메서드란 ??

public void addMember(Member member) {
     member.setTeam(this);
     members.add(member);
}
public void changeTeam(Team team) {
    this.team = team;
    team.getMembers().add(this);
}

JPAMain 코드에서

team.getMembers().add(member);
member.setTeam(team);

//순수 객체 상태를 고려해서 양쪽에 값을 입력해야 한다.
//하지만 둘 중 코드 하나를 잊어버릴수 있기 때문에, 편의 메서드를 사용하자

team.addMember(member);
//OR
member.changeTeam(team);

실전 예제 2 - 연관관계 매핑 시작

Reference
김영한 님 - 자바 ORM 표준 JPA 프로그래밍 - 기본편

profile
효율적이고 꾸준하게

0개의 댓글