[JPA] 엔티티, 연관관계 매핑

dooboocookie·2022년 10월 4일
0
post-thumbnail

요구사항

동물 병원 줄서기프로젝트를 시작했다.
그 중 맡은 부분은 병원 등록, 검색, 줄서기 기능이다.

  • 목표
    • 병원 엔티티 생성
    • 병원 1개에 여러 이미지가 등록될 수 있는 1:N 관계

엔티티 매핑

@Entity 어노테이션

  • 엔티티로 매핑할 클래스에 @Entity 어노테이션을 붙여서 JPA가 관리하도록 한다.
  • 기본 생성자는 필수
    • JPA가 객체 생성 시 기본 생성자를 사용
  • 필드나 클래스에 final 사용 X
@Entity
@NoArgsConstructor //기본생성자 롬복
class Hospital {
	
}

PK(고유키) 매핑

@Id

  • 기본키를 매핑하는 어노테이션

기본키 생성 전략

  • @GeneratedValue(strategy = GenerationType.XXXX)
  1. AUTO (기본값)
    • dialect 값에 따라 자동으로 생성
    • 오라클의 시퀀스와 같다.
  2. IDENTITY
    • 기본키 생성을 데이터베이스에서 한다.
    • MySQL,PostgreSQL,...에서 AUTO_INCREMENT를 이용
  3. SEQUENCE
    • 오라클 등에서 시퀀스를 사용하여 기본키 지정
  4. TABLE
    • PK 생성하는 테이블을 통해 관리

@Column

  • 엔티티의 필드와 DB의 컬럼을 매핑하는 어노테이션
  • name 속성
    • 컬럼명을 명시하는 속성
    • 별다른 설정이 없으면 카멜 케이스 → 언더스코어로 변경
      • ex. memberId → member_id
  • 제약조건을 관리하는 속성
    • nullable : NOT NULL
    • unique : 유일성 제약조건
    • length : 문자열의 길이
    • ...
  • updatable
    • update문 반영 여부

@Enumerated

  • Enum 클래스를 매핑
  • EnumType.ORDINAL
    • 기본값
    • enum 순서를 데이터베이스에 저장
    • enum 에 중간에 값을 추가하는 식으로 순서가 바뀌면 가르키는 값이 달라질 수 있음
  • EnumType.String
    • enum 이름을 데이터베이스에 저장
    • 이렇게 저장하는게 거의 필수
@Entity
@Getter
@NoArgsConstructor
public class Hospital {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long hosId;
    private String hosName;
    private String hosPhone;
    @Enumerated(EnumType.STRING)
    private HosStatus hosStatus;
    @Enumerated(EnumType.STRING)
    private HosBooking hosBooking;
    private String hosOpenhour;
    
}
@Entity
@Getter
@NoArgsConstructor
public class HosImg {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long himId;
    private String himPath;
    private boolean himMain;
    private String himOrigin;
    
}

연관관계 매핑

객체 연관 관계

  • 기본적인 RDBMS에서의 연관관계를 참조하면 FK 컬럼에서 참조하는 테이블의 PK를 참조한다.
  • ORM기술이 JPA 에서는 객체를 통하여 연관관계를 매핑한다.
  • 참조하는 엔티티 객체를 필드 값으로 주면 된다.
  • 현재 요구사항에선 하나의 병원을 등록할 0개 이상의 복수의 사진을 등록하는 것이므로 N:1의 연관관계를 갖는다.
  • 즉, 각 사진에는 참조하는 병원 객체를 필드 값으로 갖고 있다.

어노테이션 종류

@ManyToOne

  • 연관관계 매핑할 때 가장 기본이 되는 어노테이션
  • N:1 관계임을 명시
    속성 내용
    optional 참조하는 엔티티가 항상 있어야한다는 조건
    fetch 패치 전략에 속성인데, N+1문제를 해결할 때 자세한학습 필요
    cascade 부모객체로부터의 영속성을 전이 받을 지에 대한 여부

@OneToOne

  • 1:1관계를 명시
  • 1:1관계는 참조를 당하는 쪽도 참조를 하는 쪽도 @OneToOne의 관계를 줄 수 있다. (양방향이 됨)
    • 외래키가 있는 곳이 연관관계 주인에 대한 설정이 필요
    • (mappedBy="필드명")을 통하여 참조된 객체의 필드를 명시해 매핑

@JoinColumn

  • DB에 저장될 때 FK 컬럼의 정보를 담는 어노테이션
  • name속성 : 기본 값은 언더스코어형식으로 반영
  • referencedColumnName : 대상 테이블의

@OneToMany

  • @ManyToOne 반대 쪽에 엔티티에 명시하여 양방향 관계를 맺음
  • List<엔티티>를 필드타입으로 가져 해당 객체를 참조하는 객체들을 리스트로 담고 있다.
  • (mappedBy="필드명")을 통하여 참조된 객체의 필드를 명시해 매핑

@ManyToMany

  • M:N의 관계를 명시
  • 카테고리 같이 대,중,소 카테고리에 아이템들이 여러개 참조될 수 있을 때 사용
  • 실무에선 거의 사용하지 않음
  • 한계와 해결 방법에 대해선 나중에 추가적으로 공부할 예정

연관관계 종류

단방향

  • @ManyToOne,@OneToOne을 통하여 FK가 있는 쪽에만, 매핑 해놓은 관계
  • 가장 일반적인 경우이며, 실제 RDBMS에서 참조해놓은 상황과 가장 유사하다.
  • 1:1, N:1 둘 다 유사하다.

양방향

  • 단방향 관계에서 참조 당하는 쪽에 @OneToMany,@OneToOne을 줘서 참조하고 있는 객체를 필드 값으로 가지고 있게 함
  • 1:N의 경우 해당 객체를 참조하고 있는 객체가 N개 이므로 그 필드는 List<>
    • 해당 필드는 new ArrayList<>();를 통하여 미리 리스트를 할당해놓는게 맞음
  • 연관관계의 주인을 명시

연관관계의 주인

  • 양방향 관계에선 연관관계의 주인이 필요
  • 외래키가 있는 쪽이 연관관계의 주인이다
    • 부서사원이 있으면 FK가 있는 사원이 주인이다
@Entity
@Getter
@NoArgsConstructor
public class Hospital {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long hosId;
    private String hosName;
    private String hosPhone;
    @Enumerated(EnumType.STRING)
    private HosStatus hosStatus;
    @Enumerated(EnumType.STRING)
    private HosBooking hosBooking;
    private String hosOpenhour;
    //양방향 관계(1:N)
    @OneToMany(mappedBy = "hospital", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<HosImg> hosImgs = new ArrayList<>();
}
@Entity
@Getter
@NoArgsConstructor
public class HosImg {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long himId;
    private String himPath;
    private boolean himMain;
    private String himOrigin;
    //N:1
    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "hosId") //hosImg 테이블의 컬럼명
    private Hospital hospital;
    
}
profile
1일 1산책 1커밋

0개의 댓글