ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JPA] 연관관계
    프로그래밍/JPA 2021. 10. 20. 17:29
    반응형

    이 글은 혼자 학습한 내용을 바탕으로 작성되었습니다.

    틀리거나 잘못된 정보가 있을 수 있습니다.

    댓글로 알려주시면 수정하도록 하겠습니다.


    1. 연관관계

    JPA의 연관관계는 3가지 키워드가 있다

    • 방향
      예를 들어 회원과 팀의 관계에서  회원 -> 팀 또는 팀 -> 회원과 같은 방향을 단방향 관계라고 한다.
      회원 -> 팀, 팀 -> 회원과 같은 방향을 양방향 관계라고 한다.
      방향의 경우 객체관계에만 존재한다.
      테이블의 겨우는 항상 양방향 관계이다.

    • 다중성
      다중성에는 [다대일, 일대다, 일대일, 다대다] 4가지 다중성이 있다.
      회원과 팀의 관계에서 회원은 1개의 팀에만 속할 수 있는 경우는 회원(다) : 팀(일)인 다대일 관계가 된다.
      팀과 회원의 관계에서 회원은 1개의 팀에만 속할 수 있는 경우는 팀(일) : 회원(다)인 일대다 관계가 된다.
      회원과 팀의 관계에서 회원은 여러 팀에 속할 수 있는 경우는 회원(다) : 팀(다)인 다대다 관계가 된다.
      회원과 사물함의 관계에서 회원은 1개의 사물함만 사용가능한 경우는 회원(일) : 사물함(일)인 일대일 관계가 된다.

    • 연관관계의 주인
      객체를 양방향 관계로 만들면 연관관계의 주인을 정하여 주인만 연관관계의 키를 관리하도록 해야한다.

     

    2.  객체와 테이블의 연관관계 차이

    • 객체 관점
      회원 객체는 필드(맴버변수)로 팀 객체와 연관관계를 맺는다.
      회원 객체와 팀객체는 단방향 관계를 맺고있다.
      회원의 객체에서 팀 객체로의 접근은 가능 하지만 반대로 팀 객체에서 회원으로의 접근은 불가능 하다.

    • 테이블 관점
      회원 테이블은 외래 키로 팀 테이블과 연관관계를 맺는다.
      회원 테이블과 팀 테이블은 양방향 관계를 맺고있다.
      두 테이블은 외래 키를 가지고 서로 조인이 가능하다 회원 테이블에서 외래 키로 팀 테이블과 조인이 가능하며,
      팀 테이블에서 외래 키로 회원 테이블과 조인이 가능하다.
    • 객체의 경우는 항상 단방향이며 테이블의 경우는 항상 양방향의 방향성을 가진다.
      이러한 방향의 다름은 두 객체가 서로 참조를 하면 단방향 연관관계 2개를 통해 양방향 처럼 사용이 가능하다.

    3. 엔티티와 테이블 관계 매핑

    엔티티에 연관관계를 매핑하기 위해서는 다중성을 나타내는 어노테이션을 필수로 사용해야된다.

     

    다중성을 나타내는 어노테이션 종류

    • ManyToOne
    • OneToMany
    • ManyToMany
    • OneToOne

    외래 키로 매핑하고자 하는 경우 JoinColumn 어노테이션을 사용며 name 속성에는 매핑하고자 하는 외래 키의 이름을 지정한다.

    JoinColumn 어노테이션은 생략이 가능하다.

     

    JoinColumn 속성

    속성명 기능
    name 매핑할 외래 키 이름
    referencedColumnName 외래 키가 참조하는 대상 테이블의 컬럼명
    foreignKey 외래 키 제약조건을 직접 지정할 수 있다.

     

    4. 단방향 연관관계 사용

    • 회원 엔티티
      @Entity
      public class Memeber{
      	@Id
      	@Column(name="MEMBER_ID")
      	private String id;
          
      	private String username;
          
      	@ManyToOne
      	@JoinColumn(name="TEAM_ID")
      	private Team team;
          
      	public void setTeam(Team team){
      		this.team = team;
      	}
      }
    • 팀 엔티티
      @Entity
      public class Team {
      	@Id
      	@Column(name="TEAM_ID")
      	private String id;
          
      	private String name;
      }
    • 저장
      public void save(EntityManager em){
      	Team team1 = new Team("team1", "팀1");
      	em.persist(team1);
          
      	Member member1 = new Member("member1", "회원1");
      	member1.setTeam(team1);
      	em.persist(member1);
          
      	Member member2 = new Member("member2", "회원2");
      	member1.setTeam(team1);
      	em.persist(member1);
      }
      회원 엔티티(member1)에 setTeam메소드를 통해 팀 엔티티를 참조 하도록 하고 저장했다.
      JPA는 참조한 팀의 식별자(ID)를 외래 키로 사용해서 등록 쿼리를 생성하여 회원 엔티티를 저장 한다.
    • 조회
      연관관계가 있는 인티티를 조회하는 방법은 크게 2가지가 있다.
      1. 객체 그래프 탐색
      2. 객체 지향 쿼리 사용

    • 객체 그래프 탐색
      member 엔티티의 getTeam 메소드를 사용해서 member 엔티티와 연관된 team 엔티티를 조회할 수 있다.
      이처럼 객체를 통해 연관된 엔티티를 조회하는 것을 객체 그래프 탐색이라고 한다.

    • 객체 지향 쿼리 사용(JPQL)
      private static void jpqlQuery(EntityManager em){
      	String jpql = "select m from Memeber m join m.team t where " + "t.name=:teamName";
          
      	List<Member> resultList = em.createQuery(jpql, Memeber.class)
      		.setParameter("teamName", "팀1");
      		.getResultList();
          
      	for(Member member : resultList)
      		System.out.println(member.getUsername());
      }
      jpql 문자열을 해석하면 회원과 팀의 관계를 가지고 있는 필드를 통해 Member와 Team을 조인하고 where절을 통해 검색조건으로 팀명이 팀1인 팀에 속한 회원만 검색했다.

      jpql을 상세히 보면 먼저 Member와 팀과의 연관관계를 맺고 있는 (m.team) 필드를 통해 Team과 조인을 한다.
      그 이후 where 절을 통해 팀명이 파라미터로 전달 받은 팀명과 같은 (t.name=:teamName) 팀만 골라낸다.

    • 수정
      private static void update(EntityManager em){
      	Team team2 = new Team("team2", "팀2");
      	em.persist(team2);
          
      	Member member = em.find(Member.class, "member1");
      	member.setTeam(team2);
      }
      수정의 경우 저장과 같은 메소드는 없다. 단순히 불러온 엔티티 member의 값만 변경하면 트랜잭션을 커밋할 때 플러시가 일어나면서 변경 감지 기능이 작동한다. 그 후 변경사항을 DB에 자동으로 반영한다.
    • 연관관계 제거
      private static void delete(EntityManager em){
      	Memver member = em.find(Member.class, "member1");
      	member.setTeam(null);
      }
      연관관계 제거의 경우 연관관계를 제거하고자 하는 엔티티값을 null로만 변경하면 된다.
      위 코드의 setTeam(null)을 한 것으로 JPA는 트랜잭션을 커밋할 때 변경 감지를 통해 외래 키의 값을 Null로 저장한다.

    5. 양방향 연관관계 사용

    • 회원 엔티티
      @Entity
      public class Memeber{
      	@Id
      	@Column(name="MEMBER_ID")
      	private String id;
          
      	private String username;
          
      	@ManyToOne
      	@JoinColumn(name="TEAM_ID")
      	private Team team;
          
      	public void setTeam(Team team){
      		this.team = team;
      	}
      }
    • 팀 엔티티
      @Entity
      public class Team {
      	@Id
      	@Column(name="TEAM_ID")
      	private String id;
          
      	private String name;
          
      	@OneToMany(mappedBy="team")
      	List<Member> members = new ArrayList<Member>();
      }
      단방향 과는 다르게 List 컬렉션 members를 추가했다.
      그리고 팀과 회원의 관계는 일대다 관계 이므로 OneToMany 어노테이션을 사용했다.
      또한 OneToMany 어노테이션의 속성으로 mappedBy를 사용하였는대 mappedBy는 양방향 매핑일 때 사용하는 속성으로 반대쪽(member의 팀 필드) 매핑의 필드명을 값으로 설정하면 된다.

    • 조회
      public void search(EntityManager em){
      	Team team = em.find(Team.class, "team1");
      	List<Member> members = team.getMembers();
          
      	for(Member member : members)
      		System.out.println(member.getUsername());
      }​
      팀에서 회원 컬렉션으로 객체 그래프 탐색을 사용하여 회원들을 조회가능 하다.
    • 저장, 수정, 제거
      양방향 관계의 경우 연관관계의 주인이 정해진다.
      하여 연관관계의 주인의 경우 조회, 저장, 수정, 제거 모두 가능 하지만 연관관계의 주인이 아닌 엔티티는 연관관계에 대한 조회만 가능하다.
      그러므로 팀 엔티티의 회원 엔티티들의 조회는 가능하지만 저장, 수정, 제거는 불가능 하다.

     

    반응형

    '프로그래밍 > JPA' 카테고리의 다른 글

    [JPA] 예외 처리  (0) 2021.11.05
    [JPA] 연관관계의 주인  (0) 2021.10.21
    [JPA] Entity 매핑  (0) 2021.10.17
    [JPA] 영속성 컨텍스트  (0) 2021.10.14
    [JPA] 객체와 데이터베이스의 패러다임 불일치  (0) 2021.10.09

    댓글

Designed by Tistory.