본문 바로가기
Spring

JPA 복합키 사용 방법

qbang 2021. 10. 14.
@Entity
@Table(name="board")
public class Board implements Serializable {
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private int board_num;
	private String title;
	private String content;
	private int member_num;
	private Date reg_date;
	
	// getter, setter
	...
}

보통의 엔티티에는 PK인 컬럼 위에 @Id 어노테이션을 붙인다. 

하지만 board_member에서처럼 복합키를 엔티티에 매핑하려면 어떻게 해야 할까?

 

@EmbeddedId

@Data
@Embeddable
class Board_member_id implements Serializable{
	@Column(name = "board_num")
	private int board_num;
    
	@Column(name = "member_num")
	private int member_num;
    
	public Board_member_id(){}
    
	public Board_member_id(int board_num, int member_num){
		this.board_num = board_num;
		this.member_num = member_num;
	}
    
	@Override
	public boolean equals(Object o) {
        if (this == o) 
        	return true;
        if (o == null || getClass() != o.getClass()) 
        	return false;
        
        Board_member_id id = (Board_member_id) o;
        return (board_num == id.board_num) && (member_num == id.member_num);
	}
	
	@Override
	public int hashCode() {
		return Objects.hash(board_num, member_num);
	}
}

첫번째 방법은 Embeddable 어노테이션을 이용하는 것이다. Serializable 인터페이스를 구현한 클래스를 선언하고 복합키로 사용하는 컬럼을 필드로 만든다. 그리고 Serialiable을 상속해서 equals 및 hashCode 메서드를 구현해야 한다. 해당 메서드는 영속성 컨텍스트가 식별자를 비교할 때 사용하기 때문에 반드시 오버라이딩 해야한다. 뒤에 나오겠지만 IdClass와는 다르게 Embeddable 어노테이션을 이용하는 방법은 식별자 클래스에 기본 키를 직접 매핑해야 한다. 

@Data
@Entity
class Board_member{
	@EmbeddedId
	private Board_member_id board_member_id;
}

엔티티 클래스 내부에 Embeddable 어노테이션을 이용하여 만든 클래스를 연관 관계로 설정하면 된다. 위 예제에서는 복합키를 제외한 다른 컬럼이 없지만 만약 있다면 Board_member 클래스의 필드로 들어가면 된다.

 

@IdClass

public class Board_member_id implements Serializable {
	private int board_num;
	private int member_num;
	
	@Override
	public boolean equals(Object o) {
        if (this == o) 
        	return true;
        if (o == null || getClass() != o.getClass()) 
        	return false;
        
        Board_member_id id = (Board_member_id) o;
        return (board_num == id.board_num) && (member_num == id.member_num);
	}
	
	@Override
	public int hashCode() {
		return Objects.hash(board_num, member_num);
	}
	
	//getter, setter
	...

}

IdClass 어노테이션을 이용하는 방법은 식별자 클래스의 변수명과 엔티티에서 사용되는 변수명이 동일해야 하고, 마찬가지로 Serialiable을 상속해서 equals 및 hashCode 메서드를 구현해야 한다. 

@Entity
@Table(name="board_member")
@IdClass(Board_member_id.class)
public class Board_member {
	@Id
	private int board_num;
	@Id
	private int member_num;
	
	public Board_member() {}
	
	public Board_member(Board_member_id id) {
		this.board_num = id.getBoard_num();
		this.member_num = id.getMember_num();
	}
}

그리고 엔티티 클래스에는 @IdClass 어노테이션을 이용하여 식별자 클래스를 매핑해주고 식별자 클래스의 변수명과 동일한 이름의 변수를 선언해준다.

 

@EmbededId vs @IdClass

  @EmbededId @IdClass
장점 - 객체지향적 - 명시적으로 필드 노출 가능
- 식별 관계를 여러 테이블에서 사용할 때 연관 관계를 단순하게 유지 가능
단점 - 복합키구조가 2개이상 테이블에 식별관계로 매핑될 때 복잡도 증가 - 컬럼에 대한 필드 선언이 중복 발생

 

참고

 

댓글