본문 바로가기
Spring JPA

다양한 연관관계 매핑 - 9

by 홍굴이 2021. 7. 9.

다대일

  • 다대일 단방향(N:1)
    @Entity
    public class Member {
    	
        @Id 
        @GeneratedValue
        private Long id;
    	
        @ManyToOne
        @JoinColumn(name = "team_id")
        private Team team;
        
    
    }


  • 다대일 양방향(N:1, 1:N)

    1. 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
      항상 다(N)에 외래 키가 있다. -> 다 쪽이 주인
    2. 양방향 연관관계는 항상 서로를 참조해야 한다.

일대다

  • 일대다 단방향(1:N)

    1. 일대다 단방향 매핑의 단점은 매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다는 점이다.
      즉, 본인 테이블에 외래 키가 있으면 엔티티의 저장과 연관관계 처리를 insert SQL 한 번으로 끝낼 수 있지만, 다른 테이블에 있으면 연관관계 처리를 위해 update SQL을 추가로 실행한다.
    2. 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하는 것이 좋다.

  • 일대다 양방향(1:N, N:1)

    사실 일대다 양방향 매핑은 존재하지 않는다. 하지만 완전히 불가능한 것은 아니다.
    일대다 단방향 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방향 매핑을 읽기 전용으로 하나 추가하면 된다.
    @Entity 
    public class Member { 
    	
        @Id
        @GeneratedValue 
        private Long id; 
        
        @ManyToOne 
        @JoinColumn(name = "team_id", insertable = false, updatable, false) 
        private Team team; 
    
    }

    @Entity
    public class Team {
    
        @Id
        @GeneratedValue
        private Long id;
        
        //mappedBy 속성 사용 x
        @OneToMany
        @JoinColumn(name = "team_id")
        private List<Member> memberList = new ArrayList<>();
        
    }​
     반대편인 다대일 쪽은 insertable, updatable로 읽기만 가능하게 하면된다.
    하지만 이 방법도 일대다 단방향 매핑이 가지는 단점을 그대로 가지기 때문에 추천하지 않는다.

일대일

  • 일대일 관계는 그 반대도 일대일 관계다.
  • 주 테이블이나 대상 테이블 둘 중 어느곳이나 외래 키를 가질 수 있다.

다대다

관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.

그래서 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다.

객체는 테이블과 다르게 객체 2개로 다대다 관계를 만들 수 있다.

 

다대다 : 단방향

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    
    @ManyToMany
    @JoinTable(name = "member_product",
    	joinColumns = @JoinColumn(name = "member_id"),
        inverseJoinColumns = @JoinColumn(name = "product_id"))
    private List<Product> productList = new ArrayList<>();
    
 }
  • @JoinTable.name : 연결 테이블을 지정한다.
  • @JoinTable.joinColumns : 현재 방향인 엔티티와 매핑할 조인 컬럼 정보를 지정한다.
  • @JoinTable.inverseJoinColumns : 반대 방향인 엔티티와 매핑할 조인 컬럼 정보를 지정한다.

다대다 : 양방향

@Entity
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "product_id")
    private Long id;
    
    @ManyToMany(mappedBy = "productList")
    private List<Member> memberList = new ArrayList<>();
    
}

역방향도 @ManyToMany를 사용하고 mappedBy를 지정한다.

 

다대다 : 매핑의 한계와 극복, 연결 엔티티 사용

연결 테이블에 컬럼을 추가하게 되면 더이상 @ManyToMany를 사용할 수 없다.

왜냐하면 각각 회원, 상품 엔티티에 추가한 칼럼들을 사용할 수 없기 때문이다.

그럼 결국 연결 테이블을 매핑하는 연결 엔티티를 만들고 이곳에 추가한 컬럼들은 매핑해야 한다.

그리고 엔티티 간의 관계도 테이블 관계처럼 다대다에서 일대다, 다대일 관계로 풀어야한다.

 

회원 엔티티

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    
    private String memberName;
    
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProductList
    
 }

상품 엔티티

@Entity
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "product_id")
    private Long id;
    
    private String productName;
    
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProductList
      
}

연결 엔티티

@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {

    @Id
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
    
    @Id
    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;
    
    private int orderAmount;
    private LocalDate orderDate;
    
}

회원상품 식별자 클래스

public class MemberProductId implements Serializable {

    private String member;
    private String product;
    
    @Override
    public boolean equals(Object o) { ... }
    
    @Override
    public int hashcode() { ... }
    
}

회원상품(MemberProduct.) 엔티티를 보면 기본 키를 매핑하는 @Id와 외래 키를 매핑하는 @JoinColumn을 동시에 사용해서 기본 키 + 외래 키를 한번에 매핑 했다.

그리고 @IdClass를 사용해서 복합 기본 키를 매핑했다.

 

복합 기본 키

회원상품 엔티티는 기본 키가 member_id와 product_id로 이루어진 복합 기본 키다.

JPA에서 복합 키를 사용하려면 별도의 식별자 클래스를 만들어야 한다.

  • 복합 키는 별도의 식별자 클래스로 만들어야 한다.
  • Serializable을 구현해야 한다.
  • equals와 hashCode 메소드를 구현해야 한다.
  • 기본 생성자가 있어야 한다.
  • 식별자 클래스는 public이어야 한다.
  • @IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.

 

다대다 : 새로운 기본 키 사용

위의 복합 키를 사용하는 방법 말고 추천하는 기본 키 생성 전략은 데이터베이스에서 자동으로 생성해주는 대리 키를 Long 값으로 하는 것이다.

회원 엔티티

@Entity
public class Member {

    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;
    
    private String memberName;
    
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProductList
    
 }

상품 엔티티

@Entity
public class Product {

    @Id
    @GeneratedValue
    @Column(name = "product_id")
    private Long id;
    
    private String productName;
    
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProductList
      
}

회원상품 엔티티

@Entity
public class MemberProduct {

    @Id
    @GeneratedValue
    @Column(name = "order_id")
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;
    
    @ManyToOne
    @JoinColumn(name = "product_id")
    private Product product;
    
    private int orderAmount;
    private LocalDate orderDate;
    
}

대리키를 사용함으로써 이전에 보았던 식별 관계에 복합 키를 사용하는 것보다 매핑이 단순하고 쉽다.

'Spring JPA' 카테고리의 다른 글

프록시와 연관관계 관리 - 11  (0) 2021.07.13
고급 매핑 - 10  (0) 2021.07.12
연관관계 매핑 기초 - 8  (0) 2021.07.06
엔티티 매핑 - 7  (0) 2021.07.03
영속성 관리 - 6  (0) 2021.06.29

댓글