고급 매핑

윤용운·2022년 4월 30일
1

JPA_스터디

목록 보기
7/9
post-thumbnail

7장. 고급 매핑

상속 관계 매핑

관계형 데이터베이스에서는 상속이란 개념은 없지만, 슈퍼타입 서브타입 관계(Super-Type Sub-Type Relationship)라는 모델링이 상속 개념과 가장 유효하다. 슈퍼타입 서브타입 논리 모델을 테이블로 구현할 떄는 3가지 방법을 선택할 수 있다.

  • 각각의 테이블로 변환
    각각을 모두 테이블로 만들고, 조회할 떄 조인을 사용한다. JPA에서는 조인 전략이라 한다.
  • 통합 테이블로 변환
    테이블을 하나만 사용해서 통합한다. JPA에서는 단일 테이블 전략이라 한다.
  • 서브타입 테이블로 변환
    서브 타입마다 하나의 테이블을 만든다. JPA에서는 구현 클래스마다 테이블 전략이라 한다.

조인 전략

엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 기본 키를 받아서 기본 키 + 외래 키로 사용하는 전략이다.

테이블은 타입의 개념이 없으므로 DTYPE 컬럼을 구분 컬럼으로 사용한다.

@Entity
@Inheritance(strategy = InheritanceType.JOINED)	// 1
@DiscriminatorColumn(name = "DTYPE")	// 2
public abstract class Item {
    @Id @GeneratedValue
    @Column(name = "ITEM_ID")
    private Long id;
    
    private String name;
    private String price;
    ...
}

@Entity
@DiscriminatorValue("A")	// 3
public class Album extends Item {
    private String artist;
    ...
}

@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
    private String director;
    private String actor;
    ...
}![](https://velog.velcdn.com/images/yuyun0124/post/85dd6ba5-674d-40c5-bf7d-a7e71376bf8d/image.png)
  1. @Inheritance(strategy = InheritanceType.JOINED)
    상속 매핑은 부모 클래스에 @Inheritance를 사용해야 하는데, 여기서는 조인 전략을 사용하므로 nheritanceType.JOINED 사용
  2. @DiscriminatorColumn(name = "DTYPE")
    부모 클래스에 구분 컬럼 지정. 해당 컬럼으로 저장된 자식 테이블을 구분할 수 있다. 기본타입이 DTYPE이므로 @DiscriminatorColumn으로 생략해도 된다.
  3. @DiscriminatorValue("M")
    엔티티를 저장할 때 구분 컬럼에 입력할 값을 지정한다. 영화 엔티티 저장 시, DTYPE에 M이 저장된다.

기본값으로 자식 테이블은 부모 테이블의 ID 컬럼명을 그대로 사용하는데, 자식 테이블의 기본 키 컬럼명을 변경하고 싶다면 @PrimaryKeyJoinColumn을 사용하면 된다.

  • 장점
    • 테이블이 정규화된다
    • 외래 키 참조 무결성 제약조건을 활용할 수 있다
    • 저장공간을 효율적으로 사용한다.
  • 단점
    • 조회 시 조인이 많이 사용되므로 성능이 저하될 수 있다
    • 조회 쿼리가 복잡하다
    • 데이터를 등록할 INSERT SQL을 두번 실행한다
  • 특징
    JPA 표준 명세는 구분 컬럼을 사용하도록 하지만, 하이버네이트를 포함한 몇몇 구현체는 구분 컬럼 없이도 동작한다.

단일 테이블 전략

테이블을 하나만 사용하고, 구분 컬럼으로 어떤 자식 데이터가 저장되었는지 구분한다.

일반적으로 가장 빠르다고 한다.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {
    @Id @GeneratedValue
    @Column(name = "ITEM_ID")
    private Long id;

    private String name;
    private String price;
    ...
}

@Entity
@DiscriminatorValue("A")
public class Album extends Item {
    ...
}

@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
    ...
}

@Entity
@DiscriminatorValue("B")
public class Book extends Item {
    ...
}

InheritanceType.SINGLE_TABLE 지정 시 단일 테이블 전략을 사용한다. 테이블 하나에 모든 것을 통합하므로 구분 컬럼을 필수로 사용해야 한다.

  • 장점
    • 조인이 필요 없으므로 조회 성능이 빠르다
    • 조회 쿼리가 단순하다
  • 단점
    • 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다
    • 테이블 하나에 모두 저장하므로 테이블이 커질 수 있다. 상황에 따라 조회 성능이 오히려 느려질수도 있다
  • 특징
    구분 컬럼(@DiscriminatorColumn)을 꼭 사용해야 한다. 그리고 @DiscriminatorValue를 지정하지 않으면 기본으로 엔티티 이름을 사용한다.

구현 클래스마다 테이블 전략

자식 엔티티마다 테이블을 만드는 전략이다.

자식 테이블 각각에 필요한 컬럼이 모두 있다.

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
    @Id @GeneratedValue
    @Column(name = "ITEM_ID")
    private Long id;

    private String name;
    private String price;
    ...
}

@Entity
public class Album extends Item {
    ...
}

@Entity
public class Movie extends Item {
    ...
}

@Entity
public class Book extends Item {
    ...
}

일반적으로 추천하지 않는 전략이다.

  • 장점
    • 서브 타입을 구분해서 처리할 때 효과적이다.
    • not null 제약조건을 사용할 수 있다.
  • 단점
    • 여러 자식 테이블을 함께 조회할 때 성능이 느리다(UNION 사용)
    • 자식 테이블을 통합해서 쿼리하기 어렵다.
  • 특징
    구분 컬럼을 사용하지 않는다.

@MappedSuperclass

지금까지는 부모 클래스와 자식 클래스를 모두 데이터베이서 테이블과 매핑했지만, 부모 클래스는 테이블과 매핑하지 않고 자식 클래스에게 매핑 정보만 제공하는 방법도 있다. 바로 @MappedSuperclass를 사용하는 것이다.

위의 그림에서 회원과 판매자는 서로 관계가 없는 테이블과 엔티티이다. 테이블은 그대로 두고, 객체 모델의 id, name 두 공통 속성을 부모 클래스로 모으고, 객체 상속 관계로 만들 수 있다.

@MappedSuperclass
public abstract class BaseEntity {
    @Id @GeneratedValue
    private Long id;
    private String name;
    ...
}

@Entity
@AttributeOverride(name = "id", column = @Column(name = "MEMBER_ID"))
public class Member extends BaseEntity {
	// ID 상속
    // NAME 상속
    private String email;
    ...
}

@Entity
@AttributeOverrides({
	@AttributeOverride(name = "id", column = @Column(name = "SELLER_ID")),
    @AttributeOverride(name = "name", column = @Column(name = "SELLER_NAME"))
})
public class Seller extends BaseEntity {
	// ID 상속
    // NAME 상속
    private String shopName;
    ...
}
  • BaseEntity
    테이블과 매핑할 필요 없이 자식 엔티티에게 공통으로 사용되는 매핑 정보만 제공하면 된다. 따라서 @MappedSuperclass를 사용하였다.
  • Member
    부모로부터 물려받은 매핑 정보를 재정의하려면 @AttributeOverride를 사용하여 재정의할수 있다.
  • Seller
    둘 이상의 매핑 정보를 재정의하려면 @AttributeOverrides를 사용하면 된다.
  • 추가적으로, 연관관계를 재정의하고 싶다면 @AssociationOverrides@AssociationOverride를 사용하면 된다.

@MappedSuperclass의 특징은 다음과 같다.

  • 테이블과 매핑되지 않고, 자식 클래스에 엔티티의 매핑 정보를 상속하기 위해 사용
  • @MappedSuperclass로 지정한 클래스는 엔티티가 아니므로 em.find()나 JPQL에서 사용 불가
  • 해당 클래스를 직접 생성해서 사용할 일은 거의 없으므로 추상 클래스로 만드는 것을 권장한다.

테이블과는 관계가 없고, 단순히 엔티티가 공통으로 사용하는 매핑 정보를 모아주는 역할을 한다. ORM에서 이야기하는 진정한 상속 매핑은 위에서 이야기한 슈퍼타입 서브타입 관계와 매핑하면 된다. 하지만 등록일자, 수정일자, 등록자, 수정자 같은 여러 엔티티에서 공통으로 사용하는 속성을 효과적으로 관리할 수 있다.

복합 키와 식별관계 매핑

식별관계 vs 비식별관계

  • 식별 관계
    부모 테이블의 기본 키를 내려받아서 자식 테이블의 기본 키 + 외래 키로 사용하는 관계

  • 비식별 관계
    부모 테이블의 기본 키를 받아서 자식 테이블의 외래 키로만 사용하는 관계

    • 필수적 비식별 관계 : 외래 키에 NULL을 허용하지 않는다. 연관관계를 필수적으로 맺어야 한다.
    • 선택적 비식별 관계 : 외래 키에 NULL을 허용한다. 연관관계를 맺을지 말지 선택할 수 있다.

복합 키 : 비식별 관계 매핑

@Entity
public class Hello {
	@Id
    private String id1;
    @Id
    private String id2;	// 실행 시점에서 매핑 예외 발생
}

복합 키는 다음과 같이 매핑하면 될 것 같지만, 이렇게 사용하게 되면 매핑 예외(org.hibernate.MappingException)가 발생한다.

영속성 컨텍스트에 엔티티를 보관할 때 엔티티의 식별자를 키로 사용하는데, 식별자를 구분하기 위해 equalshashCode를 사용해 동등성 비교를 하는데, 식별자 필드가 하나일 때는 문제가 없지만(보통 자바의 기본 타입을 사용하므로), 식별자 필드가 2개 이상이면 별도의 식별자 클래스를 만들고 그곳에 equalshashCode를 구현해줘야 한다.

@IdClass

관계형 데이터베이스에 가까운 방법이다.

@Entity
@IdClass(ParentId.class)
public class Parent {
	@Id
    @Column(name = "PARENT_ID1")
    private String id1;
    
	@Id
    @Column(name = "PARENT_ID2")
    private String id2;
    
    private String name;
    ...
}

// 식별자 클래스
public class ParentId implements Serializable {
	private String id1;
    private String id2;
    
    public ParentId() {}
    
    public ParentId(String id1, String id2) {
    	this.id1 = id1;
        this.id2 = id2;
    }
    
    @Override
    public boolean equals(Object o) {...}
    
    @Override
    public int hashCode() {...}
}

식별자 클래스는 다음 조건을 만족해야 한다.

  • 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 한다.

    Parent.id1과 ParentId.id1, Parent.id2과 ParentId.id2

  • Serializable 인터페이스 구현
  • equals, hashCode 구현
  • 기본 생성자가 있어야 한다.
  • 식별자 클래스는 public이어야 한다.

복합 키를 사용해서 저장할 때 ParentId 클래스를 사용하지 않아도 영속성 컨텍스트에서 알아서 생성해서 영속성 컨텍스트의 키로 사용해준다. 조회 시에는 ParentId를 사용해서 조회할 수 있다.

부모 테이블의 기본 키 컬럼이 복합 키이므로 자식 테이블의 외래 키도 복합 키이다. 따라서 외래 키 매핑시 여러 컬럼을 매핑해야 하므로 @JoinColumns을 사용하면 된다.

@Entity
public class Child {
	@Id
    private String id;
    
    @ManyToOne
    @JoinColumns({
    	@JoinColumn(name = "PARENT_ID1", referencedColumnName = "PARENT_ID1"),
    	@JoinColumn(name = "PARENT_ID2", referencedColumnName = "PARENT_ID2")
    })
    private Parent parent;
}

@JoinColumnname 속성과 referencedColumnName 속성값이 같으면 referencedColumnName은 생략해도 된다.

@EmbeddedId

@IdClass와 비교해서 좀 더 객체지향적인 방법이다.

@Entity
public class Parent {
	@EmbeddedId
    private ParentId id;
    
    private String name;
    ...
}

// 식별자 클래스
@Embeddable
public class ParentId implements Serializable {
	@Column(name = "PARENT_ID1")
	private String id1;
    
	@Column(name = "PARENT_ID2")
    private String id2;
    
    // 생성자
    // equals, hashCode
    ...
}

@IdClass와는 다르게 식별자 클래스에 기본 키를 직접 매핑한다. 따라서, @IdClass와 달리 저장시에도 ParentId를 직접 사용해서 저장을 해주어야 한다. 조회시에는 @IdClass와 동일하다.

복합 키 사용 시, equalshashCode를 적절히 오버라이딩해야 영속성 컨텍스트가 엔티티를 적절히 관리 할 수 있다.

@IdClass@EmbeddedId는 각각 장단점이 있으므로 본인의 취향에 맞는 것을 일관성있게 사용하면 좋다.

복합 키에는 @GenerateValue를 사용할 수 없다.

복합 키 : 식별 관계 매핑

부모, 자식, 손자까지 계속 기본 키를 전달하는 식별 관계이다. @IdClass@EmbeddedId를 사용해서 식별자를 매핑해야 한다.

@IdClass

// 부모
@Entity
public class Parent{
	@Id @Column(name = "PARENT_ID")
	private String id;
    
    private String name;
	...
}

// 자식
@Entity
@IdClass(ChildId.class)
public class Child{
	@Id
	@ManyToOne
	@JoinColumn(name = "PARENT_ID")
	private Parent parent;
	
	@Id @Column(name = "CHILD_ID")
	private String childId;
    
    private String name;
	...
}

// 자식 ID
public class ChildId implements Serializable{
	private String parent; // Child.parent 매핑
	private String childId; // Child.childId 매핑
	
	// equals, hashCode
	...
}

// 손자
@Entity
@IdClass(GrandChildId.class)
public class GrandChild{
	@Id
	@ManyToOne
	@JoinColumns({
		@JoinColumn(name = "PARENT_ID"),
		@JoinCOlumn(name = "CHILD_ID")
	})
	private Child child;
	
	@Id @Column(name = "GRANDCHILD_ID")
	private String id;
	
	...
}

// 손자 ID
public class GrandChildId implements Serializable{
	private ChildId child; // GrandChild.child 매핑
	private String id; // GrandChild.id 매핑
	
	// equals, hashCode
	...
}

식별 관계는 기본 키와 외래 키를 같이 매핑해야 하므로, 식별자 매핑인 @Id와 연관관계 매핑인 @ManyToOne을 같이 사용하여야 한다.

@EmbeddedId

@EmbeddedId로 식별 관계 구성시에는 @MapsId를 사용해야 한다.

// 부모
@Entity
public class Parent{
	@Id @Column(name = "PARENT_ID")
	private String id;
	...
}

// 자식
@Entity
public class Child{
	@EmbeddedId
	private ChildId id;
	
	@MapsId("parentId") // ChildId.parentId 매핑
	@ManyToOne
	@JoinColumn(name = "PARENT_ID")
	public Parent parent;
	
	...
}

// 자식 ID
@Embeddable
public class ChildId implements Serializable{
	private String parentId; // @MapsId("parentId")로 매핑
	
	@Column(name = "CHILD_ID")
	private String id;
	
	// equals, hashCode
	...
}

// 손자
@Entity
public class GrandChild{
	@EmbeddedId
	private GrandChildId id;
	
	@MapId("childId") // GrandCHildId.childId 매핑
	@ManyToOne
	@JoinColumns({
		@JoinColumn(name = "PARENT_ID"),
		@JoinColumn(name = "CHILD_ID")
	})
	private Child child;
	
	...
}

// 손자 ID
@Embeddable
public class GrandChildId implements Serializable{
	private ChildId childId; // @MapsId("childId") 매핑
	
	@Column(name = GRANDCHILD_ID)
	private String id;
	
	...
}

@IdClass와의 차이점은 @Id 대신 @MapsId를 사용하였다는 것이다. @MapsId의 속성값은 @EmbeddedId를 사용한 식별자 클래스의 기본 키 필드를 지정하면 된다.

비식별 관계로 구현

// 부모
@Entity
public class Parent{
	@Id @GeneratedValue
	@Column(name = "PARENT_ID")
	private Long id;
	private String name;
	...
}

// 자식
@Entity
public class Child{
	@Id @GeneratedValue
	@Column(name "CHILD_ID")
	private Long id;
	private String name;
	
	@ManyToOne
	@JoinColumn(name = "PARENT_ID")
	private Parent parent;
	...
}

// 손자
@Entity
public class GrandChild{
	@Id @GeneratedValue
	@Column(name = "GRANDCHILD_ID")
	private Long id;
	private String name;
	
	@ManyToOne
	@JoinColumn(name = "CHILD_ID")
	private Child child;
	...
}

복합 키가 없으므로 복합 키 클래스를 만들지 않아도 되고, 따라서 매핑도 쉽고 코드도 간단해진다.

일대일 식별 관계.


자식 테이블의 기본 키 값으로 부모 테이블의 기본 키 값만 사용한다. 따라서 부모 테이블의 기본 키가 복합 키가 아니라면 자식 테이블의 기본 키는 복합 키로 구성하지 않아도 된다.

// 부모
@Entity
public class Board{
	@Id @GeneratedValue
	@Column(name = "BOARD_ID")
	private Long id;
	
	private String title;
	
	@OneToOne(mappedBy = "board")
	private BoardDetail boardDetail;
	...
}

// 자식
@Entity
public class BoardDetail{
	@Id
	private Long boardId;
	
	@MapsId // BoardDetail.boardId 매핑
	@OneToOne
	@JoinColumn(name = "BOARD_ID")
	private Board board;
	
	private String content;
	...
}

식별, 비식별 관계의 장단점

  • 식별 관계는 부모 테이블의 기본 키를 자식 테이블로 전파하면서 자식 테이블의 기본 키 컬럼이 늘어난다. 이에 따라 조인 시 SQL이 복잡해지고 기본 키 인덱스가 불필요하게 커질 수 있다.
  • 식별 관계는 2개 이상의 컬럼을 합해서 복합 기본 키를 만들어야 하는 경우가 많다
  • 식별 관계 사용 시 기본 키로 비즈니스 의미가 있는 자연 키 컬럼을 조합하는 경우가 많지만, 비식별 관계의 기본 키는 비즈니스와 전혀 관계가 없는 대리 키를 주로 사용한다. 비즈니스 요구사항은 시간이 지남에 따라 바뀔 가능성이 있고, 이에 따라 자연 키 컬럼들이 많이 전파되면 변경하기 힘들어진다.
  • 식별 관계는 비식별 관계보다 테이블 구조가 유연하지 못하다.
  • JPA에서 복합 키는 별도의 클래스를 만들어서 사용해야 한다. 이에 따라 많은 노력이 필요하다.
  • 비식별 관계의 기본키는 주로 대리 키를 사용하는데, JPA는 @GenerateValue처럼 대리 키를 생성하기 위한 편리한 방법을 제공한다.

물론, 식별 관계가 가지는 장점도 존재한다.

  • 특정 상황에서 조인 없이 하위 테이블만으로 검색을 할 수 있다.
  • 별도의 인덱스를 생성할 필요 없이 기본 키 인덱스만 사용해도 된다.

따라서, 적절한 상황에서 적절히 사용하는 것이 좋다.

선택적 비식별 관계보다 필수적 비식별 관계를 사용하는 것이 좋다. 선택적 비식별 관계는 NULL을 허용하므로 조인 시 외부 조인을 사용해야 하지만, 필수적 관계는 NOT NULL이므로 항상 관계가 있다는 것을 보장해주기 때문에 내부 조인만 사용해도 된다.

조인 테이블

데이터베이스 테이블의 연관관계를 설계하는 방법은 크게 2가지다.

  • 조인 컬럼 사용
    테이블 간 관계는 주로 조인 컬럼이라 부르는 외래 키 컬럼을 사용해서 관리한다. 객체와 테이블 매핑 시 @JoinColumn으로 매핑한다.
  • 조인 테이블 사용
    별도의 테이블을 사용해서 연관관계를 관리하는 방법이다. 매핑 시 @JoinTable을 사용한다. 주로 다대다 관계를 일대다-다대일 관계로 풀어내기 위해 사용하나, 일대일, 일대다, 다대다 관계에서도 사용한다.

일대일 조인 테이블

조인 테이블의 외래 키 컬럼 각각에 총 2개의 유니크 제약조건을 걸어야 한다.

// 부모
@Entity
public class Parent{
	@Id @GeneratedValue
	@Column(name = "PARENT_ID")
	private Long id;
	private String name;
	
	@OneToOne
	@JoinTable(name = "PARENT_CHILD",	// 1
		joinColumns = @JoinColumn(name = "PARENT_ID"),	// 2
		inverseJoinColumns = @JoinColumn(name = "CHILD_ID"))	//3 
	private Child child;
	...
}

// 자식
@Entity
public class Child{
	@Id @GeneratedValue
	@Column(name = "CHILD_ID")
	private Long id;
	private String name;
	...
}
  1. name
    매핑할 조인 테이블 이름
  2. joinColumns
    현재 엔티티를 참조하는 외래 키
  3. inverseJoinColumns
    반대방향 엔티티를 참조하는 외래 키

양방향으로 매핑하려면 @OneToOne(mappedBy="child")로 매핑하면 된다.

일대다 조인 테이블

조인 테이블의 컬럼 중 다(N)와 관련된 컬럼에 유니크 제약조건을 걸어야 한다.

// 부모
@Entity
public class Parent{
	@Id @GeneratedValue
	@Column(name = "PARENT_ID")
	private Long id;
	private String name;
	
	@OneToMany
	@JoinTable(name = "PARENT_CHILD",
		joinColumns = @JoinColumn(name = "PARENT_ID"),
		inverseJoinColumns = @JoinColumn(name = "CHILD_ID"))
	private List<Child> child = new ArrayList<Child>();
}

// 자식
@Entity
public class Child{
	@Id @GeneratedValue
	@Column(name = "CHILD_ID")
	private Long id;
	private String name;
	...
}

다대일 조인 테이블

일대다에서 방향만 반대이므로 테이블 모양은 일대다와 같다.

// 부모
@Entity
public class Parent{
	@Id @GeneratedValue
	@Column(name = "PARENT_ID")
	private Long id;
	private String name;
	
	@OneToMany(mappedBy = "parent")
	private List<Child> child = new ArrayList<Child>();
	...
}

// 자식
@Entity
public class Child{
	@Id @GeneratedValue
	@Column(name = "CHILD_ID")
	private Long id;
	private String name;
	
	@ManyToOne(optional = false)
	@JoinTable(name = "PARENT_CHILD",
		joinColumns = @JoinColumn(name = "CHILD_ID"),
		inverseJoinColumns = @JoinColumn(name = "PARENT_ID"))
	private Parent parent;
	...
}
  • @ManyToOne(optional = false)
    optional 속성을 false로 설정하게 되면 해당 객체에 null이 들어갈 수 없다. 따라서, parent가 필수적으로 들어가게 되므로 INNER JOIN 쿼리가 생성된다.

다대다 조인 테이블

다대다 조인 테이블을 만드려면 조인 테이블의 두 컬럼을 합해서 하나의 복합 유니크 제약조건을 걸어야 한다.

// 부모
@Entity
public class Parent{
	@Id @GeneratedValue
	@Column(name = "PARENT_ID")
	private Long id;
	private String name;
	
	@ManyToMany
	@JoinTable(name = "PARENT_CHILD",
		joinColumns = @JoinColumn(name = "PARENT_ID"),
		inverseJoinColumns = @JoinColumn(name = "CHILD_ID"))
	private List<Child> child = new ArrayList<Child>();
	...
}

// 자식
@Entity
public class Child{
	@Id @GeneratedValue
	@Column(name = "CHILD_ID")
	private Long id;
	private String name;
	...
}

조인테이블에 컬럼이 추가되면 @JoinTable전략을 사용 할 수 없다. 대신 새로운 엔티티를 생성해서 조인 테이블과 매핑해야 한다.

엔티티 하나에 여러 테이블 매핑

@SecondaryTable을 사용하면 한 엔티티에 여러 테이블을 매핑할 수 있다.

@Entity
@Table(name = "BOARD") // BOARD 테이블과 매핑
@SecondaryTable(name = "BOARD_DETAIL", // 매핑할 다른 테이블의 이름
	pkJoinColumns = @PrimaryKeyJoinColumn(name = "BOARD_DETAIL_ID")) // 다른 테이블의 기본 키명
public class Board{
	@Id @GeneratedValue
	@Column(name = "BOARD_ID")
	private Long id;
	
	private String title;
	
	@Column(table = "BOARD_DETAIL")
	private String content;
}
  • @SecondaryTable.name
    매핑할 다른 테이블의 이름
  • @SecondaryTable.pkJoinColumns
    매핑할 다른 테이블의 기본 키 컬럼 속성

더 많은 테이블을 매핑하려면 @SecondaryTables를 사용하면 된다.

@SecondaryTables({
	@SecondaryTable(name = "BOARD_DETAIL"),
    @SecondaryTable(name = "BOARD_FILE")
})

두 테이블을 하나의 엔티티에 매핑하는 방법보다 테이블당 엔티티를 각각 만들어 일대일 매핑하는 것을 권장한다. 해당 방법은 항상 두 테이블을 조회하므로 최적화하기 어렵고, 일대일 매핑은 원하는 부분만 조회할 수 있고 필요하면 둘 다 조회하면 되기 때문이다.

Reference

  • 자바 ORM 표준 JPA 프로그래밍 (김영한)

0개의 댓글