[JPA 프로그래밍 - 기본편] 연관관계 매핑 기초

지현·2022년 2월 4일
0

JPA

목록 보기
5/12

방향(Direction) : 단방향, 양방향
다중성(Multiplicity) : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)
연관관계의 주인(Owner) : 객체 양방향 연관관계는 관리 주인이 필요

1:N의 관계일 때, 외래키가 있는 쪽이 N


연관관계가 필요한 이유

객체를 테이블에 맞추어 모델링을 하면 문제점 존재

  • 외래 키 식별자를 직접 다룸
		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);

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

  • 테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾음
  • 객체는 참조를 사용해서 연관된 객체를 찾음
  • 테이블과 객체 사이에는 큰 간극이 존재

단방향 연관관계

관계가 무엇인지와 이 관계로 연관될 때 DB에서 join하는 컬럼은 무엇인지 작성

@Entity
public class Member {
	
    ...

    @ManyToOne //Member가 n, Team이 one인 관계
    @JoinColumn(name = "TEAM_ID") //join하는 컬럼
    private Team team;

	...
    
}

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

            Member member=new Member();
            member.setUsername("member1");
            member.setTeam(team);

            em.persist(member);

			//조회
            Member findMember = em.find(Member.class, member.getId());
            Team findTeam=findMember.getTeam();
            System.out.println("findTeam = " + findTeam.getName());
            ts.commit();
  • teamId(외래키)가 아닌 참조값으로 저장, 조회 등 가능

객체의 참조와 DB의 외래키를 연관관계를 통해 매핑 가능!!

양방향 연관관계와 연관관계의 주인

테이블의 연관관계는 외래키 하나로 양방향이 존재 (FK 하나를 사용하면 양쪽으로 다 알 수 있음)
객체는 Team에 List members를 넣어줘야 양쪽으로 갈 수 있음 (Team과 Member에 둘 다 세팅해줘야 양쪽으로 갈 수 있음)

@Entity
public class Member {
	
    ...

    @ManyToOne //Member가 n, Team이 one인 관계
    @JoinColumn(name = "TEAM_ID") //join하는 컬럼
    private Team team;

	...
    
}
@Entity
public class Team {
    @Id @GeneratedValue @Column(name = "TEAM_ID")

	...
    
    @OneToMany(mappedBy = "team") //mappedBy > 뭐랑 연결되어있는지? (Member 객체의 team)
    private List<Member> members=new ArrayList<>();
    
    ...
    
}
    Member findMember = em.find(Member.class, member.getId());
    List<Member> members = findMember.getTeam().getMembers(); //역방향 조회

연관관계의 주인(Owner)

  • 객체의 양방향 관계는 서로 다른 단뱡향 관계 2개
    객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 함
  • 테이블은 외래 키 하나로 두 테이블의 연관관계를 관리

둘 중 하나로 외래키를 관리!!

양방향 매핑 규칙

  • 객체의 두 관계중 하나를 연관관계의 주인으로 지정
  • 연관관계의 주인만이 외래 키를 관리(등록, 수정)
  • 주인이 아닌쪽은 읽기, 조회하는 것은 가능, 변경은 X
  • 주인은 mappedBy 속성 사용 X
  • 주인이 아니면 mappedBy 속성으로 주인 지정
  • 외래키가 있는 쪽 (1:n일때 n쪽)을 연관관계 주인으로 설정하는것이 좋음

주의점

  • 양방향 매핑시 연관관계 주인인 곳에 값을 꼭 넣어야함 (주인이 아닌곳은 읽기만 가능해서 이쪽에만 넣으면 오류)
  • 순수한 객체 관계를 고려하면 항상 양쪽다 값을 입력
    • 양방향 매핑시 무한 루프 주의
      • 롬복에서 toString() 만드는 것 웬만하면 사용 X, 컨트롤러에는 엔티티 반환 X
    • 양쪽 다 값을 입력 하려면 연관관계 편의 메소드를 생성하는것이 편함
      			//changeTeam만 호출해도 양방향으로 값을 설정할 수 있도록 편의 메소드를 생성
      			public void changeTeam(Team team){
      				this.team=team;
       				team.getMembers().add(this);
      			}
     - 연관관계 편의 메소드는 1쪽에 생성해서 넣어도 되고 n쪽에 넣어도 됨
  • 예시) Member, Team이 n : 1 관계일 때
    • 외래키는 Member쪽에 있으므로 연관관계의 주인은 Member
    • Member에 team을 넣고 JPA로 DB에 저장되면 Team에도 Member의 값이 저장됨(양방향 연결)
    • Member에 team을 넣고나서 아직 commit하지 않아 DB에는 반영되지 않았는데 Team에 저장된 Member를 꺼내면, Team은 1차 캐시에 저장되어 있는것을 불러오는 것이므로 아직 Member와 연결되지 않아 값이 없음
  • JPA에서의 설계에서는 단방향 매핑만으로도 연관관계 매핑 완료
  • 단방향 매핑을 잘 하고 양방향은 필요할 때 추가해도 됨 (테이블에 영향을 주지 않음)
  • 할 수 있으면 최대한 단방향으로 해라 !!
  • 비즈니스 로직을 기준으로 연관관계의 주인을 선택하면 안됨
  • 연관관계의 주인은 외래 키의 위치를 기준으로 정해야함


출처
[인프런] 자바 ORM 표준 JPA 프로그래밍 - 기본편

0개의 댓글

관련 채용 정보