연관관계 매핑

ttomy·2022년 2월 15일
0

연관관계 매핑

배울 것: @ManyToOne,@OneToMany,@JoinColumn,연관관계의 주인,(mappedBy="필드이름"), 양방향 연관관계에서 양방향의 객체까지 고려

연관관계

  • 방향
    [단방향,양방향] 이 있다. 회원->팀,팀->회원 을 다 알수 있는 것이 양방향이고, 둘 중 한 방향으로만 알 수 있는것이 단방향이다.
  • 다중성
    [일대일,일대다,다대일,다대다] 가 있다. 팀에 여러 회원이 있다면 회원과 팀은 다대일 관계이다.
  • 연관관계의 주인
    양방향의 연관관계가 있다면 연관관계의 주인을 정해야한다. 이는 외래키를 관리할 주체가 누구냐하는 문제로, 다대일 관계에서는 주로 다인 쪽이 주인이 된다.

객체는 참조를 이용해 관계를 맺고 테이블은 외래키를 이용해 관계를 맺는다. 이때 참조는 단방향이지만 외래키는 join한 범위를 모두 알 수 있으므로 사실상 양방향이라 할 수 있다.(A join B 와 B join A 의 범위는 같다.)
아래 그림에서 Member.getTeam() 으로 멤버는 팀을 알지만 Team에서는 Member를 알 수 없으므로 단방향이다.

Jpa에서 위와 같은 Entity를 정의할 떄

@Entity
public class Member {

    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String username;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

이와 같은 방식으로 정의한다. 이떄 DB의 테이블에서 어떤 필드를 외래키로 할지 알아햐 하기에 @JoinColumn을 붙여준다.
--@JoinColumn을 생략하면 기본전략이 사용된다.
필드명_참조하는 테이블의 칼럼명이 자동으로 외래키로 사용된다.--

연관관계 있는 엔티티 조회

두 방법이 있다.

객체 그래프 탐색

member.getTeam() 처럼 객체를 통해 조회하는 방법이다.

객체지향 쿼리 사용(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("teamName","팀1");
    .getResultList();

엔티티매니저.createQuery에 jpql을 넣어 조회하는 방법이다.

연관관계 엔티티 수정

em.update() 같은 메소드는 없다. jpa는 영속상태의 엔티티가 수정된다면 트랜잭션이 commit될때 알아서 쿼리를 실행해 DB에서의 내용도 수정한다.

양방향 연관관계


위 그림처럼 member에서 team을, team에서 members를 알 수 있는게 양방향의 연관관계이다. 하지만 table에서는 단방향일 떄와 변함없이 외래키만
연결되어 있으면 된다.

연관관계의 주인

양방향 관계가 있는 두 테이블 중 외래키를 등록,수정,삭제 등의 관리를 할 수 있는 주체를 정해야 한다. 이것이 왜 필요할까?
예를 들어 Team테이블에서 Member를 관리해야 한다고 가정하자. Team에는 Member_ID가 존재하지 않으므로 물리적으로 다른 테이블의 필드를 관리해야 괴리가 생긴다. 때문에 외래키가 있는 곳의 테이블을 주인으로 선택해야 한다. 주인이 아니면 @OneToMany(mappedBy="team")과 같이 주인이 아님을 작성해야 한다.

--다만 객체에서는 연관관계의 주인이 아니더라도 참조 객체에 접근할 수 있으므로 객체에서는 양쪽의 데이터를 모두 update하는 것이 좋다.

ex)
member1.SetTeam("Team1") 을 한다고 해서 자동으로
Team1.getMemeber() 의 값에 반영되지는 않기에 Team1.getMember().add("Team1")을 해주어야 한다.

--또한 member의 팀을 Team1에서 Team2로 바꾼 경우, member 객체의 Team을 바꾸는 것은 물론 Team1의 List< Member >또한 바꿔야 한다. 이처럼 양방향의 연관관계는 정교,꼼꼼한 로직이 필요하다.

다양한 연관관계 매핑

다대일 양방향

위에서 언급했듯 양방향 연관관계에서 서로를 어긋나지 않게 참조하게 위해
setTeam,addMember 같은 편의 메소드를 작성할 수 있는데, 이떄 무한루프에 빠지지 않도록 검사하는 것이 안전하다.

일대다 단방향

일대다 단방향의 경우 외래키가 자기 테이블에 없기에 연관관계를 반영하기 위한 쿼리를 한 번 더 수행해야 한다. 떄문에 가능하면 다대일 양방향 매핑을 이용하도록 하자.

일대일

일대일 양방향 매핑의 경우 외래키가 주테이블,대상 테이블 중 어디에나 위치할 수 있다. 다만 장단점이 있다.

  • 주테이블에 외래키
    객체 참조와 유사하게 사용가능하다. 주테이블만 확인해도 연관관계를 확인할 수 있다.
  • 대상 테이블에 외래키
    일대일에서 일대다 관계로 확장을 할 떄 테이블 구조를 유지한 채로 변경가능하다.

다대다

@ManyToMany
@JoinTable(name,joinColumns,inverseJoinColumns),

관계형 DB는 다대다 관계를 표현할 수 없다. 때문에 중간에 연결 테이블을 두어 일대다와 다대일의 관계로 풀어낸다.

manyTomany 매핑의 한게와 극복


위 그림처럼 연결테이블에 ID만이 아닌 다른 관리필드까지 필요한 경우가 많다. 때문에 OneToMany,ManyToOne으로 연결된 위 그림처럼 연결테이블을 만든다. 식별자도 연결테이블의 ID를 따로 만들고 member와 product의 id는 외래키로만 사용하는 것이 더 단순하고 명확한 방법이다.

0개의 댓글