7장. 고급 매핑

7.1 상속 관계 매핑

  • 관계형 DB에는 상속이라는 개념 X
  • ORM 에서 얘기하는 상속 관계 매핑은 객체의 상속구조DB의 슈퍼타입 서브타입 관계를 매핑하는 것

  • 슈퍼타입 서브타입 논리 모델을 실제 물리 모델인 테이블로 구현시 아래와 같은 3가지 방법중 선택 가능
    • 각각의 테이블로 변환: 각각을 모두 테이블로 만들고 조회할 때 조인을 사용. => 조인 전략
    • 통합 테이블로 변환: 테이블을 하나만 사용해서 통합. => 단일 테이블 전략
    • 서브타입 테이블로 변환: 서브타입마다 하나의 테이블을 만듬. => 구현 클래스마다 테이블 전략



7.1.1 조인 전략

  • 엔티티 각각을 모두 테이블로 만들고 자식 테이블이 부모 테이블의 pk 를 pk & fk 로 사용
  • ∴ 조회 시 조인을 자주 사용
  • !!주의사항!!: 객체는 타입으로 구분할 수 있지만 테이블엔 타입 개념이 없으므로 타입 구분 컬럼 필요함
    • 위 예제의 경우 dtype column 이 타입 구분용 컬럼
코드
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "dtype")
public abstract class Item {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private int price;

    ...
}

...

@Entity
@DiscriminatorValue("A")
@PrimaryKeyJoinColumn(name = "item_id")
public class Albumn extends Item {
    private String artist;

    ...
}

...

@Entity
@DiscriminatorValue("M")
@PrimaryKeyJoinColumn(name = "item_id")
public class Movie extends Item {
    private String director;
    private String actor;

    ...
}

...

@Entity
@DiscriminatorValue("B")
@PrimaryKeyJoinColumn(name = "item_id")
public class Book extends Item {
    private String author;
    private String isbn;

    ...
}

  • @Inheritance(strategy = InheritanceType.JOINED): 상속 매핑시 부모 클래스에 @Inheritance 사용해야 함
    • 또한 매핑 전략 지정해줘야 하는데 위 예제에서는 조인 전략을 사용하기 위해 InheritanceType.JOINED 설정
  • @DiscriminatorColumn(name = “dtype”): 부모 클래스에 구분 컬럼을 지정
    • 기본 값은 DTYPE
  • @DiscriminatorValue(“M”): 엔티티 저장시 구분 컬럼에 입력할 값을 지정
    • 여기 설정한 값이 구분 컬럼(위 예제에선 dtype) 에 저장됨
  • @PrimaryKeyJoinColumn(“item_id”): 자식 테이블의 pk 컬럼명 변경하기 위해 사용
    • 기본 값으로는 부모 테이블의 id 컬럼명을 그대로 사용


조인전략 장/단점 및 특징

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



7.1.2 단일 테이블 전략

  • 테이블을 하나만 사용
  • 구분 컬럼으로 어떤 자식 데이터가 저장되었는지 구분
  • !!주의사항!!: 자식 엔티티가 매핑한 컬럼은 모두 null 사용해야 함
    • 다른 자식 엔티티와 매핑된 컬럼은 null로 비워둬야 하기 때문
코드
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
public abstract class Item {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private int price;

    ...
}

...

@Entity
@DiscriminatorValue("A")
public class Albumn extends Item {
    private String artist;

    ...
}

...

@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
    private String director;
    private String actor;

    ...
}

...

@Entity
@DiscriminatorValue("B")
public class Book extends Item {
    private String author;
    private String isbn;

    ...
}

  • @Inheritance(strategy = InheritanceType.SINGLE_TABLE): 단일 테이블 전략은 InhertianceType.SINGLE_TABLE 로 설정
  • 구분 컬럼은 필수


단일 테이블 전략 장/단점 및 특징

  • 장점:
    • 조인 필요없어 일반적으로 조회 성능이 빠름
    • 조회 쿼리가 단순
  • 단점:
    • 자식 엔티티가 매핑한 컬럼은 모두 null 허용해야 함
    • 단일 테이블에 다 저장해서 테이블이 커질 수 있음 => 상황에 따라 조회 성능 더 느려질 수도
  • 특징:
    • 구분 컬럼 필수. 따라서 @DiscriminatorColumn 꼭 설정해야 함
    • @DiscriminatorValue 지정 안하면 default 값은 엔티티 이름



7.1.3 구현 클래스마다 테이블 전략 (Table-per-Concrete-Class Strategy)

  • 자식 엔티티마다 테이블 만듬
  • 자식 테이블 각각에 필요한 컬럼 모두 생성
코드
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
    @Id
    @GeneratedValue
    private Long id;

    private String name;
    private int price;

    ...
}

...

@Entity
public class Albumn extends Item {
    private String artist;

    ...
}

...

@Entity
public class Movie extends Item {
    private String director;
    private String actor;

    ...
}

...

@Entity
public class Book extends Item {
    private String author;
    private String isbn;

    ...
}

  • @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS): 구현 클래스마다 테이블 전략은 InheritanceType.TABLE_PER_CLASS 로 설정


구현 클래스마다 테이블 전략 장/단점 및 특징

  • 장점:
    • 서브 타입 구분해서 처리시 효과적
    • not null 제약조건 사용 가능
  • 단점:
    • 여러 자식 테이블 함께 조회 시 성능 안좋음(UNION 사용해야 하기 때문)
    • 자식 테이블 통합해서 쿼리하기 어려움
  • 특징
    • 구분 컬럼 사용안함




7.2 @MappedSuperclass

  • 부모 클래스는 테이블과 매핑하지 않고 상속받는 자식 클래스에게 매핑 정보만 제공하려면 @MappedSuperclass 사용

코드
@MappedSuperclass
public abstract class BaseEntity {
    @Id
    @GeneratedValue
    private Long id;
    private String name;

    ...
}

...

@Entity
public class Member extends BaseEntity {
    // id 상속
    // name 상속
    private String email;

    ...
}

...

@Entity
public class Seler extends BaseEntity {
    // id 상속
    // name 상속
    private String shopName;

    ...
}

  • BaseEntity 에는 객체들이 주로 사용하는 공통 매핑 정보 정의
  • 자식 엔티티에서 상속으로 BaseEntity의 매핑 정보 물려받음
  • BaseEntity 는 테이블과 매핑 X
  • 상속받은 매핑 정보 재정의 하려면 @AttributeOverride 또는 @AttributeOverrides 사용
  • 연관관계 재정의 하려면 @AssociationOverride@AssociationOverrides 사용
코드
@Entity
@AttributeOverride(name = "id", column = @Column(name = "member_id"))
public class Member extends BaseEntity { ... }

  • 위 예시처럼 @AttributeOverride 를 써서 상속받은 id 속성 컬럼명을 재정의 할 수 있음
코드
@Entity
@AttributeOverrides({
    @AttributeOverride(name = "id", column = @Column(name = "member_id")),
    @AttributeOverride(name = "name", column = @Column(name = "member_name"))
})

public class Member extends BaseEntity { ... }

  • 둘 이상을 재정의 하려면 @AttrubuteOverrides 사용


@MappedSuperclass 특징

  • 테이블과 매핑되지 않고 매핑 정보 상속 위해 사용
  • @MappedSuperclass 로 지정한 클래스는 엔티티 아니어서 em.find()나 JPQL 에서 사용 불가
  • 이 클래스를 직접 생성, 사용할 일 거의 없으므로 추상 클래스로 만드는 것이 권장됨
  • 이걸 사용해서 등록일자, 수정일자, 등록자, 수정자 같은 공통 속성 효과적으로 관리 가능

@Entity는 @Entity 또는 @MappedSuperclass 로 지정한 클래스만 상속받을 수 있음




7.3 복합 키와 식별 관계 매핑

7.3.1 식별 관계 vs 비식별 관계

  • DB 테이블 사이의 관계는 fk가 pk에 포함되는지 여부에 따라 식별/비식별로 구분
  • 최근에는 비식별 관계를 주로 사용하고 꼭 필요한 곳에만 식별 관계 사용하는 추세
  • JPA 에서는 식별, 비식별 관계 둘 다 지원함

식별 관계

  • 부모 테이블 pk 내려받아 자식 테이블 pk + fk 로 사용하는 관계

  • 예제의 경우 parent 테이블의 pk id 받아서 child 테이블의 pk & fk 로 사용


비식별 관계

  • 부모 테이블 pk 내려받아 자식 테이블의 fk 로만 사용하는 관계

  • 예제의 경우 parent 테이블의 pk id 받아서 child 테이블의 fk 로만 사용
  • 비식별 관계는 (필수적 선택적) 비식별 관계로 나뉨
    • 필수적 비식별 관계(Mandatory): 외래키 non-null. 연관관계 필수
    • 선택적 비식별 관계(Optional): 외래키 nullable. 연관관계 맺을지 여부 선택 가능



7.3.2 복합키: 비식별 관계 매핑

  • ch6에서 나온 것 처럼 JPA에서 복합키 쓰려면 @IdClass 를 쓰거나 @EmbeddedId 사용해야 함
  • !!아래에 나오는 예제들에서 parent, child 는 객체 상속이랑은 무관함


@IdClass

  • 관계형 DB에 가까운 방식

코드
@Entity
@IdClass(ParentId.class)
public class Parent {
    @Id
    @Column(name = "parent_id1")
    pirvate Stirng id1;     // ParentId.id1과 연결

    @Id
    @Colu,n(name = "parent_id2")
    private String id2;

    private String name;    // ParentId.id2와 연결

    ...
}

...

public class ParentId implements Serializable {
    private String id1;     // Parent.id1 매핑
    private String id2;     // Parent.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() { ... }

    ...
}

...

@Entity
public class Child {
    @Id
    @Column(name = "child_id")
    private String id;

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "parent_id1",
            referencedColumnName = "parent_id1"),   // name이랑 referencedColumnName 같으면 생략 가능
        @JoinColumn(name = "parent_id2",
            referencedColumnName = "parent_id2")
    })
    private Parent parent;

    ...
}

...

// 저장
public void save() {
    Parent parent = new Parent("myId1", "myId2");
    parent.setName("parentName");
    // ParentId 따로 만들어주지 않아도 em.persist 호출하면 
    // 영속성 컨텍스트에 엔티티 등록 직전 내부에서 Parent.id1, Parent.id2 값으로 
    // 식별자 클래스인 ParentId 생성하여 영속성 컨텍스트 키로 사용
    em.persist(parent);

}

// 조회
public void find() {
    ParentId parentId = new ParentId("myId1", "myId2");
    Parent parent = em.find(Parent.class, parentId);
}

  • @IdClass 식별자 클래스의 조건
    • 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 함
      • ex) Parent.id1 == ParentId.id1, Parent.id2 == ParentId.id2
    • Serializable 인터페이스 implements 하고, equals, hashCode override 해야 함
    • 기본 생성자 있어야 함
    • public 이어야 함


@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 and hashCode 구현

    ...
}

// 저장
public void save() {
    Parent parent = new Parent();
    ParentId parentId = new ParentId("myId1", "myId2");
    parent.setId(parentId);
    parent.setName("parentName");
    em.persist(parent);
}

...

// 조회
public void find() {
    ParentId parentId = new ParentId("myId1", "myId2");
    Parent parent = em.find(Parent.class, parentId);
}

  • @EmbeddedId 사용시 식별자 클래스 조건
    • @Embeddable 어노테이션 붙여야 함
    • Serializable 인터페이스 구현 및 equals, hashCode 구현
    • 기본 생성자 있어야 함
    • public 이어야 함
  • @EmbeddedId 사용시에는 식별자 클래스를 직접 쓰고 @EmbeddedId 어노테이션 붙여주면 됨
  • 저장 시 @IdClass 랑 달리 식별자 클래스 직접 생성해서 사용함

복합키에는 @GenerateValue 사용 불가. 복합키 구성 요소 컬럼 중 하나에도 X



7.3.3 복합키: 식별 관계 매핑

  • 부모 -> 자식 -> 손자 까지 계속 기본키 전달하는 식별관계 예제
  • 7.3.2와 마찬가지로 @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
    @Column(name = "child_id")
    private String childId;

    @Id
    @ManyToOne
    @JoinColumn(name = "parent_id")
    public Parent parent;

    private String name;

    ...
}

...

public class ChildId implements Serializable {
    private String childId; // Child.childId 매핑
    private String parent;  // Child.parent 매핑

    // equals and hashCode

    ...
}

...

@Entity
@IdClass(GrandChildId.class)
public class GrandChild {
    @Id
    @Column(name = "grandchild_id")
    private String id;

    @Id
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "parent_id"),
        @JoinColumn(name = "child_id")
    })
    private Child child;

    private String name;

    ...
}

...

public class GrandChildId implements Serializable {
    private String id;          // GrandChild.id 매핑
    private ChildId child;    // GrandChild.child 매핑

    // equals and hashCode

    ...
}

  • 식별 관계는 pk와 fk 를 같이 매핑해야 함
    • ∴ 식별자 매핑인 @Id 와 연관관계 매핑인 @ManyToOne을 같이 사용하여 동시에 매핑


@EmbeddedId 와 식별 관계

  • @EmbeddedId로 식별 관계 구성시에는 @MapsId 사용해야 함
코드
@Entity
public class Parent {
    @Id
    @Column(name = "parent_id")
    private String id;

    private String name;

    ...
}

...

@Entity
public class Child {
    @EmbeddedId
    private ChildId id;

    @MapsID("parentId")
    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;

    private String name;

    ...
}

...

@Embeddable
public class ChildId implements Serializable {
    @Column(name = "child_id")
    private String id;

    private String parentId;    // @MapsId("parentId") 로 매핑

    // equals and hashCode

    ...
}

...

@Entity
public class GrandChild {
    @EmbeddedId
    private GrandChildId id;

    @MapsId("childId")      // GrandChildId.childId 매핑
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "parent_id"),
        @JoinColumn(name = "child_id")
    })
    private Child child;

    private String name;

    ...
}

...

@Embeddable
public class GrandChildId implements Serializable {
    @Column("grandchild_id")
    private String id;

    private ChildId childId;      // @MapsId("childId") 로 매핑

    // equals and hashCode

    ...
}
  • @IdClass 와 달리 @Id 대신 @MapsId 를 사용함
    • @MapsId 는 fk 와 매핑한 연관관계를 pk 에도 매핑하겠다는 의미
    • 속성값으로는 @EmbeddedId 를 사용한 식별자 클래스의 pk 필드 지정하면 됨
      • 위 예제의 경우 ChildId.parentId 필드



7.3.4 비식별 관계로 구현

코드
@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 Stirng name;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;

    ...
}

...

@Entity
public class GrandChild {
    @Id
    @GenertateValue
    @Column(name = "grandchild_id")
    private Long id;
    
    private String name;

    @ManyToOne
    @JoinColumn(name = "child_id")
    private Child child;

    ...
}
  • 식별 관계의 복합 키를 사용한 코드에 비해 훨씬 간단함



7.3.5 일대일 식별관계

  • 일대일 식별 관계는 부모 테이블 pk 만 자식 테이블의 pk & fk 로 사용하기 때문에 부모 테이블 기본키가 복합키 아니면 복합키로 구성하지 않아도 됨
코드
@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;

    ...
}
  • BoardDetail처럼 식별자가 단순 컬럼 하나면 @MapsId사용하고 속성 값 비워두면 됨



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

  • DB 설계 관점에서는 아래 이유들로 비식별 관계를 선호
    • pk 를 자식 테이블로 전파하면서 점점 pk 컬럼 늘어남
      • 이로 인해 조인 복잡해지고 pk 인덱스 불필요하게 커질 수 있음
    • 2개 이상 컬럼 합해 복합 기본키 만들어야하는 경우가 많음
    • 기본키로 비즈니스 의미가 있는 자연 키 컬럼 조합하는 경우가 많은데, 이런 건 좋지 않음
      • 대리키 쓰는게 좋다
  • 객체 지향 관점에서는 아래 이유들로 비식별 관계를 선호
    • 일대일 관계 제외하고는 복합 기본키를 사용하여 매핑 복잡해짐
    • 비식별 관계를 쓰면 @GenerateValue 로 대리키 편하게 사용 가능
  • 식별 관계의 장점
    • 기본 키 인덱스 활용도가 좋고 특정 상황에 조인 없이 하위 테이블 만으로 검색 가능
  • 결론적으로 그냥 비식별 관계 쓰고 대리키 사용하는 게 좋다
    • 또한 선택적 비식별 보단 필수적 비식별 관계가 항상 관계 있음 보장되어서 inner join 만 해도 돼서 좋다고 함




7.4 조인 테이블

  • DB 테이블 연관관계 설계 방식은 다음 2가지
    • 조인 컬럼 사용(FK)
    • 조인 테이블 사용(테이블 사용)


조인 컬럼 사용

  • @JoinColumn 으로 매핑
  • 연관관계를 조인 컬럼(fk 컬럼) 으로 관리
  • fk에 null 허용하는 관계 == 선택적 비식별 관계
    • 이 경우 outer join 써야 함
    • 연관관계 많지 않으면 null 로 저장되는 경우가 대부분이라는 단점 있음


  • @JoinTable 로 매핑
  • 조인 테이블이라는 별도 테이블을 두고 두 테이블의 fk 로 연관관계 관리
  • 테이블을 하나 추가해야 해서 관리해야 할 것도, 조인할 것도 늘어난 다는 단점 있음
  • 주로 N:N 을 1:N, N:1 로 풀어내기 위해 사용



7.4.1 1:1 조인 테이블

코드
@Entity
public class Parent {
    @Id
    @GeneratedValue
    @Column(name = "parent_id")
    private Long id;

    private String name;

    @OneToOne
    @JoinTable(name = "parent_child",
        joinColumns = @JoinColumn(name = "parent_id"),
        inverseJoinColumns = @JoinColumn(name = "child_id"))
    private Child child;

    ...
}

...

@Entity
public class Child {
    @Id
    @GeneratedValue
    @Column(name = "child_id")
    private Long id;

    private String name;

    private Parent parent;

    ...
}
  • 1:1 조인테이블 단방향 매핑 예제
  • 양방향으로 매핑하려면 Child.parent 위에 @OneToOne(mappedBy="child") 추가

  • @JoinTable 속성
속성 설명
name 매핑할 조인 테이블 이름
joinColumns 현재 엔티티를 참조하는 외래 키
inverseJoinColumns 반대방향 엔티티를 참조하는 외래 키



7.4.2 1: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;

    ...
}
  • 1:N 단방향 조인 테이블 매핑 예제
  • 1:N 관계 만들려면 조인 테이블 컬럼 중 N 쪽 컬럼(위 예제에선 child_id)에 유니크 제약조건 걸어야 함
    • 예제 child_id 는 pk 라 유니크 제약조건 걸려있음



7.4.3 N:1 조인 테이블

코드
@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"))
    priavte Parent parent;

    ...
}
  • N:1, 1:N 양방향 조인 테이블 매핑 예제



7.4.4 N:N 조인 테이블

코드
@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;

    ..
}
  • N:N 조인 테이블 매핑 예제
  • N:N 관계 만들려면 조인 테이블의 두 컬럼 합쳐서 하나의 복합 유니크 제약 걸어야 함
    • 위 예제의 (parent_id, child_id 는 복합 기본키라 유니크 제약조건 걸려있음)

조인 테이블에 컬럼 추가시 @JoinTable 전략 사용 불가
엔티티 새로 만들어서 조인 테이블이랑 매핑해야 함




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

  • @SecondaryTable, @SecondaryTables 를 사용하여 한 엔티티에 여러 테이블 매핑 가능
    • 이거로 두 테이블을 하나의 엔티티에 매핑하는 것보다 테이블당 엔티티 만들어서 매핑하는게 더 효율적
    • 하나에 매핑하면 항상 두 테이블 조회해서 최적화 어려움

코드
@Entity
@Table(name = "board")      // Board 엔티티를 board 테이블과 매핑
@SecondaryTable(name = "board_detail",      // board_detail 테이블과 추가 매핑
    pkJoinColumns = @PraimaryKeyJoinColumn(name = "board_detail_id"))
/** 두 개 이상 매핑하려면 @SecondaryTables 사용하면 됨
  *
  * @SecondaryTables({
  *     @SecondaryTable(name = "board_detail"),
  *     @SecondaryTable(name = "board_file")})
  */
public class Board {
    @Id
    @GeneratedValue
    @Column(name = "board_id")
    private Long id;

    @Column(table = "board_detail")     // board_detail 테이블의 content 컬럼에 매핑
    private String content;

    private String title;       // title 처럼 따로 지정 안해주면 기본 테이블(여기선 board)에 매핑

    ...
}
  • @SecondaryTable 속성
속성 설명
name 매핑할 다른 테이블의 이름
pkJoinColumns 매핑할 다른 테이블의 pk 컬럼