Spring/Spring Data JPA

[자바 ORM 표준 JPA 프로그래밍] 6. 다양한 연관관계 매핑

noahkim_ 2023. 12. 27. 20:14

김영한 님의 "자바 ORM 표준 JPA 프로그래밍" 책을 정리한 포스팅 입니다.

 

1. 다대일

  • 여러 개의 엔티티가 하나의 동일한 엔티티와 연관될 수 있는 관계

 

단방향 [N:1]

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

 

양방향 [N:1, 1:N]

@ManyToOne
@JoinColumn(name=”TEAM_ID”)
private Team team;
@OneToMany(mappedBy="team")
private List<Member> members = new ArrayList<Member>();
  • 양방향은 외래 키가 있는 쪽이 연관관계의 주인입니다.
  • 양방향 연관관계는 항상 서로를 참조해야 합니다.

 

2. 일대다

  • 하나의 동일한 엔티티가 여러 개의 엔티티와 연관될 수 있는 관계

 

단방향 [1:N]

@OneToMany(mappedBy="team")
private List<Member> members = new ArrayList<Member>();
  • Member 테이블의 TEAM_ID를 외래키로 참조하여 연관 member들을 List로 받아옵니다.
  • insert시, member의 TEAM_ID를 직접 갱신해 주어야 합니다.

 

3. 일대일

  • 양쪽이 서로 하나의 관계만 가집니다.
@Entity
public class Member {
 
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;
 
    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    Locker locker;
}
@Entity
public class Locker {
 
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "LOCKER_ID")
    private Long id;
 
    private String name;
}

 

 

4. 다대다

단방향

  • 연결 테이블을 사용합니다. (테이블 두 개로 다대다 관계를 표현 X)

 

@JoinTable
name 연결테이블 이름을 지정합니다.
joinColumns 현재 방향의 조인 컬럼 정보를 지정합니다.
inverseJoinColumns 반대 방향의 조인 컬럼 정보를 지정합니다.
@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private String id;
    
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT",
    			joinColumns = @JoinColumn(name = "MEMBER_ID"),
                	inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> products = new ArrayList<Product>();    

	//...
}
@Entity
public class Product {
    @Id
    @Column(name = "PRODUCT_ID")
    private String id;
    
    private String name;    
    ...        
 }

 

 

양방향

  • 다대다 매핑이므로 역방향도 @ManyToMany 사용합니다.
  • 주인 설정(mappedBy)(원하는 곳)
@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private String id;
    
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT",
    			joinColumns = @JoinColumn(name = "MEMBER_ID"),
                	inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> products = new ArrayList<Product>();    

	//...
}
@Entity
public class Product {
    @Id
    @Column(name = "PRODUCT_ID")
    private String id;
    
    private String name;    
    
    @ManyToMany(mappedBy = "products")
    private List<Member> members;    
    ...        
 }

 

연결 엔티티 (연결 테이블 매핑 한계 극복)

  • @JoinTable을 통해 연결 테이블을 생성할 경우, 정보성 컬럼을 추가하는 것이 어렵습니다.
  • 식별관계를 구성하여 연결 엔티티를 생성합니다.

 

식별 관계
  • 복합 외래키를 복합 기본키로 사용합니다.

 

연결 엔티티
  • 연결 엔티티를 만들고 이곳에 추가한 컬럼들을 매핑해야 합니다.
  • 다대다 관계를 양방향으로 풀어야 함 (일대다, 다대일)

 

@IdClass
  • 복합 기본키 매핑을 설정하는 어노테이션 입니다.
@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {

    @Id
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;  //MemberProductId.member와 연결
    
    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;  //MemberProductId.product와 연결    
    
    private int orderAmount;
    private DateTime createdDate;
    // ...
}

 

 

복합 기본키 식별자 클래스
  • Serializable 구현
  • default constructor, equals(), hashCode() 구현
public class MemberProductId implements Serializable {

    private String member;  //MemberProduct.member와 연결
    private String product; //MemberProduct.product와 연결   
    
    @Override
    public boolean equals(Object o) {...}
    
    @Override
    public int hashCode() {...}
}