ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 고급 매핑
    IT/JPA 2020. 12. 19. 12:52

    1. 상속 관계 매핑

      1) 조인 전략

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

       - 데이터베이스 조회할 때에는 조인을 자주 사용한다.

       - 객체는 타입으로 구분할 수 있지만 테이블은 타입의 개념이 없다.

       - 타입을 구분하는 컬럼(DTYPE)의 추가가 필요하다.

    JOIN 전략

    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    @DiscriminatorColumn(name = "DTYPE")
    public abstract class Item {
    	@Id @GeneratedValue
        @Column(name = "ITEM_ID")
        private Long id;
        
        private String name;
        ....
    }
    
    @Entity
    @discriminatorValue("A")
    public class Album extends Item {
    	private String artist;
        ...
    }
    
    @Entity
    @DiscriminatorValue("M")
    public class Movie extends Item {
    	private String director;
        private String actor;
        ....
    }

       - @Inheritance(strategy = InheritanceType.JOINED) : 상속 매핑은 부모 클래스에 @Inheritance 를 사용해야 한다.

          매팽 전략을 지정해야 하는데 JOINED 를 사용했다.

       - @DiscriminatorColumn(name="DTYPE") : 부모 클래스에 구분 컬럼을 지정한다. 기본 값이 DTYPE 이므로

            @DiscriminatorColumn 으로 줄여서 사용해도 된다.

       - @DiscriminatorValue("M") : 엔티티를 저장할 때 구분 컬럼(DTYPE)에 입력할 값을 지정한다.

     

    //재정의 : 자식 테이블의 기본 키 컬럼명을 변경하고 싶을때 사용
    @Entity
    @DiscriminatorValue("B")
    @PrimaryKeyJoinColumn(name="BOOK_ID")	//ID 재정의
    public class Book extends Item {
    	private String author;
        private String isbn;
    }

       - BOOK 테이블의 ITEM_ID 기본 키 컬럼명을 BOOK_ID로 변경했다.(재정의)

       - 조인 전략의 장점 : 테이블이 정규화된다, 외래 키 참조 무결성 제약조건을 활용할 수 있다, 저장 공간이 효율적이다.

       - 조인 전략의 단점 : 조회할 때 조인이 많이 사용되므로 성능이 저하될 수 있다, 쿼리가 복잡하다, 데이터를 등록할 때

         INSERT SQL을 두번 실행한다.

       - JPA 표준 명세는 구분 컬럼을 사용하도록 하지만, 하이버네이트를 포함한 몇몇 구현체는 구분 컬럼

          (@discriminatorColumn) 없이도 동작한다.

       - 관련 어노테이션 : @PrimaryKeyJoinColumn, @DiscriminatorColumn, @DiscriminatorValue

     

      2) 단일 테이블 전략

       - 테이블 하나만 사용한다.

       - 구분 컬럼(DTYPE)으로 어떤 자식데이터가 저장되었는지 구분한다.

       - 조회할 때 조인을 사용하지 않으므로 일반적으로 가장 빠르다.

    단일 테이블 전략

       - 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다. (Book 엔티티를 쓰면 다른 컬럼은 null로 들어가기 때문)

    @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 int 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 { ... }

       - 테이블 하나에 모든 것을 통합하므로 구분 컬럼을 필수로 사용해야 한다.

       - 장점 : 조인이 필요 없어 빠르다, 조회 쿼리가 단순하다.

       - 단점 : 자식 엔티티가 매핑한 컬럼은 모두 null을 허용해야 한다, 테이블이 커질 수 있어 상황에 따라 느려질 수 있다.

       - 구분 컬럼을 꼭 사용해야 한다. 따라서 @DiscriminatorColumn 을 꼭 설정해야 한다.

       - @DiscriminatorValue를 지정하지 않으면 기본으로 엔티티 이름을 사용한다. (Album, Movie, Book)

     

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

       - 자식 엔티티 마다 테이블을 만들고, 각 테이블에 필요한 컬럼이 모두 있다.

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

    @Entity
    @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
    public abstract class Item {
    	@Id @GeneratedValue
        @Column(name = "ITEM_ID")
        private Long id;
        
        private String name;
        private int price;
        ...
    }
    
    @Entity
    public class Album extends Item { ... }
    
    @Entity
    public class Movie extends Item { ... }
    
    @Entity
    public class Book extends Item { ... }

       - 장점 : 서브 타입을 구분해서 처리할 때 효과적이다, not null 제약조건을 사용할 수 있다.

       - 단점 : 여러 자식테이블을 함께 조회할 때 성능이 느리다(SQL에 UNION을 사용해야 한다).

       - 구분 컬럼을 사용하지 않는다.

       - 이 전략은 데이터베이스 설계자와 ORM 전문가 둘 다 추천하지 않는 전략이다.

     

    2) @MappedSuperclass

      1) @MappedSuperclass

       - 부모 클래스를 테이블과 매핑하지 않고 상속받는 자식클래스에게 매핑정보만 제공하고 싶으면

         @MappedSuperclass 를 사용한다.

       - 단순히 맵핑정보를 상속할 목적으로만 사용한다.

       - 회원과 판매자는 서로 관계가 없는 테이블과 엔티티이다.

       - id, name 두 공통 속성을 부모 클래스로 모으고 객체 상속관계로 만든다.

    @MappedSuperclass
    public abstract class BaseEntity {
    	@Id @GeneratedValue
        private Long id;
        private String name;
        ...
    }
    
    @Entity
    public class Member extends BaseEntity {
    	private String email;
        ...
    }
    
    @Entity
    public class Seller extends BaseEntity {
    	private String shopName;
        ...
    }

       - BaseEntity에는 객체들이 주로 사용하는 공통 매핑 정보를 정의했다.

       - 자식 엔티티들은 상속을 통해 BaseEntity의 매핑 정보를 물려받았다.

       - BaseEntity는 테이블과 매핑하지 않고, 자식 엔티티에게 공통으로 사용되는 매핑 정보만 제공한다.

       - 부모로부터 물려받은 매핑 정보를 재정의하려면 @AttributeOverrides나 @AttributeOverride 를 사용하고,

         연관관계를 재정의하려면 @AssociationOverrides나 @AssociationOverride를 사용한다.

    @Entity
    @AttributeOverride(name="id", column=@Column(name="MEMBER_ID"))
    public class Member extends BaseEntity {...}

       - 부모에게 상속받은 id 속성의 컬럼명을 MEMBER_ID로 재정의했다. 둘 이상을 재정의 하려면 아래와 같다.

    @Entity
    @AttributeOverrides({
    	@AttributeOverride(name="id", column=@Column(name="MEMBER_ID")),
        @AttributeOverride(name="name", column=@Column(name="MEMBER_NAME"))
    })
    public class Member extends BaseEntity { ... }

       - @MappedSuperclass는 테이블과 매핑되지 않고 자식 클래스에 엔티티의 매핑 정보를 상속하기 위해 사용한다.

       - @MappedSuperclass로 지정한 클래스는 엔티티가 아니므로 em.find()나 JPQL에 사용할 수 없다.

       - 이 클래스를 직접 생성해서 사용할 일은 거의 없으므로 추상 클래스로 만드는 것을 권장한다.

       - 엔티티(@Entity)는 엔티티(@Entity)이거나 @MappedSuperclass로 지정한 클래스만 상속받을 수 있다.

     

    3. 복합 키와 식별 관계 매핑

      1) 식별관계 vs 비식별 관계

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

       - 비식별관계 : 부모 테이블의 기본 키를 받아서 자식 테이블의 외래키로만 사용하는 관계이다. 필수적 비식별 관계 와

         선택적 비식별 관계로 나뉜다.

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

       - 선택적 비식별 관계 : 외래 키에 NULL을 허용한다. 연관관계를 맺을지 말지 선택할 수 있다.

     

      2) 복합 키: 비식별 관계 매핑

       - 둘 이상의 컬럼으로 구성된 복합 기본 키는 별도의 식별자 클래스를 만들어야 한다.

       - JPA는 영속성 컨텍스트에 엔티티를 보관할 때 식별자를 키로 사용한다. 그리고 식별자를 구분하기 위해 equals 와

         hashCode 를 사용해서 동등성 비교를 한다.

       - 식별자 필드가 하나일 때는 보통 자바의 기본 타입을 사용하므로 문제가 없지만, 2개 이상이면 식별자 클래스를

         만들고 equals 와 hashCode 를 구현해야 한다.

       - JPA는 복합 키를 지원하기 위해 @IdClass와 @EmbededId 2가지 방법을 제공하는데, @IdClass는 관계형 데이터

         베이스에 가까운 방법이고 @EmbededId는 좀 더 객체 지향에 가까운 방법이다.

     

      3) @IdClass (복합 키: 비식별관계)

       - 복합 키 테이블은 비식별 관계고, PARENT는 복합 기본 키를 사용한다.

    @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) { ... }
        
        @Oberride
        public boolean hashCode() {...}
    }

       - @IdClass를 사용할 때 식별자 클래스는 다음 조건을 만족해야 한다.

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

       - Serializable 인터페이스를 구현해야 한다.

       - equals, hashCode 인터페이스를 구현해야 한다.

       - 기본 생성자가 있어야 한다.

       - 식별자 클래스는 public이어야 한다.

    // 복합키를 사용하는 엔티티 저장
    Parent parent = new Parent();
    parent.setId1("myId1");
    parent.setId2("myId2");
    parent.setName("parentName");
    em.persist(parent);

       - em.persist()를 호출하면 영속석 컨텍스트에 엔티티를 등록하기 직전에 내부에서 Parent.id1, Parent.id2 값을 사용해

          서 식별자 클래스인 ParentId를 생성하고 영속성 컨텍스트의 키로 사용한다.

    // 복합키를 사용한 조회
    ParentId parentId = new ParentId("myId1","myId2");
    Parent parent = em.find(Parent.class, parentId);
    // 자식 클래스 (상속 관계 아님)
    @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;
        ...
    }

       - 부모 테이블의 기본 키 컬럼이 복합 키 이므로 자식 테이블의 외래 키도 복합 키다.

       - 외래 키 매핑 시 여러 컬럼을 매핑해야 하므로 @JoinColumns 어노테이션을 사용하고 각각을 @JoinColumn 으로

         매핑한다.

       - @JoinColumn의 name 속성과 referencedColumnName 속성의 값이 같으면 referencedColumnName은 생략해도   

          된다.

     

      4) @EmbeddedId (복합키: 비식별관계)

       - @IdClass가 데이터베이스에 맞춘 방법이라면 @EmbededdId는 좀 더 객체지향적인 방법이다.

    @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 구현
        ...
    }

       - @EmbeddedId를 적용한 식별자 클래스는 식별자 클래스에 기본키를 직접 매핑한다.

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

       - @Embeddable 어노테이션을 붙여주어야 한다.

       - Serializable 인터페이스를 구현해야 한다.

       - equals, hashCode를 구현해야 한다.

       - 기본 생성자가 있어야 한다.

       - 식별자 클래스는 public 이어야 한다.

    // 엔티티 저장
    Parent parent = new Parent();
    ParentId parentId = new ParentId("myId1", "myId2");
    parent.setId(parentId);
    parent.setName("parentName");
    em.persist(parent);
    
    //엔티티 조회
    ParentId parentId = new ParentId("myId1","myId2");
    Parent parent = em.find(Parent.class, parentId);

     

     5) 복합키와 equals(), hashCode()

       - 영속성 컨텍스트는 엔티티의 식별자를 키로 사용해서 엔티티를 관리하며, 식별자를 비교할때 equals() 와

          hashCode() 를 사용한다.

       - 복합 키는 equals() 와 hashCode()를 필수로 구현해야 한다. (자바의 기본은 인스턴스 참조 값 비교인 == 를

          사용하는데, 이것은 복합키의 동일성을 판단하는데 맞지 않는다. )

     

     6) @IdClass vs @EmbeddedId

       - @EmbeddedId 가 @IdClass와 비교해서 더 객체지향 적이고 중복도 없긴 하지만 특정상황에 JPQL이 조금 더 길어

          질 수 있다.

       - 복합 키에는 @GeneratedValue 를 사용할 수 없다. 여러 컬럼중 하나에도 사용할 수 없다.

    em.createQuery("select p.id.id1, p.id.id2 from Parent p");	//@EmbeddedId
    em.createQuery("select p.id1, p.id2 from Parent p");		//@IdClass

     

     7) 복합 키: 식별 관계 매핑

       - 부모, 자식, 손자까지 계속 기본 키를 전달하는 식별관계이다. (@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")
        public Parent parent;
        
        @Id @Column(name="CHILD_ID")
        private String childId;
        ....
    }
    
    //자식 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을 같이 사용한다.

       - Child 엔티티의 parent 필드를 보면 @Id로 기본 키를 매핑하면서 @ManyToOne과 @JoinColumn 으로 외래 키를

          같이 매핑한다.

       - @EmbeddedId와 식별관계는 다음과 같다.

    //부모
    @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;
        
        @MapsId("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="GRAND_CHILD_ID)
        private String id;
        //equals, hashCode
        ....
    }

       - @EmbeddedId는 식별 관례로 사용할 연관관계의 속성에 @MapsId를 사용하면 된다.

       - @MapsId의 속성 값은 @EmbeddedId를 사용한 식별자 클래스의 기본 키 필드를 지정하면 된다.

     

     8) 비식별 관계로 구현

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

       - 식별 관계보다 매핑도 쉽고 코드도 단순하다. 복합키 클래스를 만들지 않아도 된다.

     

     9) 일대일 식별관계

       - 일대일 식별 관계는 부모 테이블의 기본키 값만 사용한다.

       - 부모 테이블의 기본 키가 복합 키가 아니면 자식 테이블의 기본 키는 복합 키로 구상하지 않아도 된다.

    //부모
    @Entity
    public class Board{
    	@Id @GeneratedValue
        @Column(name="BOARD_ID")
        private Long id;
        
        @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;
        ....
    }
    
    //일대일 식별관계의 저장
    public void save() {
    	Board board = new Board();
        board.setTitle("제목);
        em.persist(board);
        
        BoardDetail boardDetail = new BoardDetail();
        boardDetail.setContent("내용");
        boardDetail.setBoard(board);
        em.persist(boardDetail);
    }

       - BoardDetail처럼 식별자가 단순히 컬럼 하나면 @MapsId를 사용하고 속성값은 비워둔다.

     

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

       - 다음과 같은 설계 관점에서 식별 관계보다는 비식별 관계를 선호한다.

       - 식별 관계는 부모 테이블의 기본 키를 자식 테이블로 전파하면서 자식 테이블의 기본 키 컬럼이 점점 늘어난다.

       - 조인할 때 SQL이 복잡해지고 기본 키 인덱스가 불필요하게 커질 수 있다.

       - 식별 관계는 2개 이상의 컬럼을 합해서 복합 기본 키를 만들어야 하는 경우가 많다.

       - 식별 관계는 비즈니스 의미가 있는 자연키 컬럼을 조합하는데, 시간이 지나면 변화에 대처하기 힘들다.

       - 비식별 관계의 기본키는 비즈니스와 전혀 관계 없는 대리키를 주로 사용한다.

       - 식별 관계는 별도의 복합 키 클래스를 만들어서 사용해야 하므로 노력이 많이 든다.

       - 비식별 관계의 기본 키는 @GenerateValue 처럼 편리하게 만들 수 있다.

       - 식별 관계는 특정 상황에 조인 없이 하위 테이블 검색만으로 완료할 수 있는 장점이 있다.

       - 비식별 관계를 사용하고 기본키는 Long 타입의 대리키를 사용하는 것이 추천된다.

       - 선택적 비식별 관계 보다는 필수적 비식별 관계를 사용하는 것이 좋다(NULL 허용 때문)

     

    4. 조인 테이블

     1) 조인 테이블

       - 데이터베이스 테이블의 연관관계를 설정하는 방법은 크게 '조인 컬럼 사용'(외래키), '조인 테이블 사용' 2가지다.

       - 조인 컬럼 사용

       - 회원이 사물함을 사용하기 전 까지는 MEMBER 테이블의 LOCKER_ID 외래 키에 null을 입력 해 두어야 한다.

       - 외래 키에 null을 허용하는 관계를 선택적 비식별 관계라 한다.

       - 선택적 비식별 관계는 외래 키에 null을 허용하므로 OUTER JOIN을 사용해야 한다.

       - 조인 테이블 사용

       - MEMBER_LOCKER 와 같은 별도의 테이블을 사용해서 연관관계를 관리한다.

       - MEMBER 와 LOCKER에는 외래 키 컬럼이 없다.

       - 회원이 락커를 사용할 때 MEMBER_LOCKER 테이블에만 값을 추가하면 된다.

       - 단점은 테이블이 늘어나고, JOIN 을 위해 MEMBER_LOCKER 테이블 까지 추가 조인해야 한다.

       - JPA에서 조인 컬럼은 @JoinColumn 으로, 조인 테이블은 @JoinTable 로 매핑한다.

       - 조인 테이블은 주로 다다대 관계를 일대다, 다대일 관계로 풀어내기 위해 사용한다.

     

     2) 일대일 조인 테이블

       - 일대일 관계를 만들려면 조인 테이블의 외래 키 컬럼 각각에 총 2개의 유니크 제약조건을 걸어야 한다.

    //부모
    @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;
        ...
    }

       - 부모 엔티티에 @JoinColumn 대신 @JoinTable을 사용했다.

       - name: 매핑할 조인 테이블 이름

       - joinColumns: 현재 엔티티를 참조하는 외래 키(PARENT_CHILD 테이블)

       - inverseJoinColumns: 반대방향 엔티티를 참조하는 외래 키(PARENT_CHILD 테이블)

       - 양방향 매핑은 다음 코드를 추가하면 된다.

    public class Child{
    	...
        @OneToOne(mappedBy="child")
        private Parent parent;
    }

     

     3) 일대다 조인 테이블

       - 일대다 관계를 만들려면 조인 테이블의 컬럼중 다(N)와 관련된 컬럼인 CHILD_ID에 유니크 제약을 걸어야 한다.

    //부모
    @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;
        ...
    }

     

     4) 다대일 조인 테이블

       - 다대일은 일대다에서 방향만 반대이다.

    //부모
    @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"),
            inverseJoinColumn=@JoinColumn(name="PARENT_ID")
        )
        private Parent parent;
        ...
    }

     

     5) 다대다 조인 테이블

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

    //부모
    @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 전략을 사용할 수 없다. 새로운 엔티티를 만들어서 조인 테이블과 매핑

         해야 한다.

     

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

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

    @Entity
    @Table(name="BOARD")
    @SecondaryTable(name="BOARD_DETAIL",
    	pkJoinColumns=@PrimaryKeyJoinColumns(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;
        ...
    }

       - Board 엔티티는 @Table을 사용해서 BOARD 테이블과 매핑했다

       - @SecondaryTable을 사용해서 BOARD_DETAIL 테이블을 추가로 매핑했다.

       - @SecondaryTable.name: 매핑할 다른 테이블의 이름

       - @SecondaryTable.pkJoinColumns: 매핑할 다른 테이블의 기본 키 속성

       - contetn 필드는 @Column(table="BOARD_DETAIL") 을 사용해서 매핑했다.

       - title 필드처럼 테이블을 지정하지 않으면 기본 테이블인 BOARD에 매핑된다.

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

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

       - @SecondaryTable을 사용해서 두 테이블을 하나의 엔티티에 매핑하는 방법 보다는 테이블당 엔티티를 각각 만들어

          서 일대일 매핑하는 것을 권장한다.

    'IT > JPA' 카테고리의 다른 글

    고급 주제와 성능 최적화  (0) 2021.02.28
    웹 애플리케이션과 영속성 관리  (0) 2021.01.24
    값 타입  (0) 2020.12.29
    연관관계 매핑  (0) 2020.12.08
    JPA 의 영속성 관리  (0) 2020.11.29
Designed by Tistory.