Coding/Back - Spring Framework

Spring Persistence(DataAccess) Layer : JPA 예제(ORM : 엔티티 간 관계) 3/3 #Day9

꿀딴지- 2023. 8. 30. 13:40

ORM(Object Relationa Mapping) : 자바와 RDB 간에 매핑을 위해 관계 설정이 필요

1. 객체와 테이블 간의 매핑 2. 기본키 매핑 3. 필드(멤버 변수)와 열 간의 매핑 4. 엔티티 간의 연관 관계 매핑

 

1. 객체(entity)와 테이블(table) 간의 매핑

  • (필수 class 앞) @Entity : JPA 관리 대상 엔티티 명시
  • (옵션 class 앞) @Table(name="name") : 엔티티와 매핑할 테이블 설정(default : 클래스이름 = 테이블이름)
  • (필수 field 앞) @Id : 식별자 역할을 하는 필드(멤버 변수)
  • (권고 field 앞) @GeneratedValue(strategy = GenerationType.IDENTITY) : PK 생성 전략

기본 생성자는 필수로 추가 - Spring Data JPA에서 기본 생성자가 없는 경우 에러가 발생하는 경우가 있음

중복되는 엔티티 클래스가 없고, 테이블 이름이 클래스 이름과 같을 경우에는 클래스 이름으로 사용하는 게 권장

@Entity(name = "USERS") 
@Table(name = "USERS") 
public class Member {
    @Id
    private Long memberId;
}

 

2. 기본키(pk) 매핑 : JPA에서 지원하는 기본키(PK) 생성 방법 : 해당 필드변수 위에 애너테이션 작성

  • 기본키 직접 할당 : 코드 상에서 직접 할당 @Id , 객체 생성 시 생성자에 id값 넘겨야 함
  • 기본키 자동 생성 :
    • (권고) IDENTITY(DB에서 처리 ex. MySQL - AUTO_INCREMENT) @GeneratedValue(strategy = GenerationType.IDENTITY)
    • SEQUENCE(DB 제공 시퀀스 사용) @GeneratedValue(strategy = GenerationType.SEQUENCE)
    • TABLE(별도 키 생성 테이블 사용)
    • AUTO(DB의 Dialect에 따라 적절한 전략을 자동으로 선택) @GeneratedValue(strategy = GenerationType.AUTO)

 

3. 엔티티 필드(멤버 변수)와 테이블 열 간의 매핑

@Column (생략가능- 속성default 적용)

  • nullable(default : true) : null값 허용여부
    • primitive type은 @Column 애너테이션이 생략되면 기본적으로 nullable=false
    • nullable에 대한 명시적인 설정 없이 단순히 @Column 애너테이션만 추가하면 nullable=true가 기본값이 되기 때문에 주의
  • updatable(default : true) : 열 데이터 수정여부(false면 update불가)
  • unique(default : false) : unique 제약조건 설정(true 면 고유값)
  • length(default : 255) : 저장할 수 있는 문자열 길이
  • name : 엔티티 클래스 필드명과 다른 이름으로 열을 생성

@Transient : 테이블 열과 매핑하지 않음

  • 저장, 조회 시 DB와 매핑되지 않음
  • 임시 데이터를 메모리에서 사용하기 위한 용도

@Enumerated : enum 타입과 매핑

  • EnumType.ORDINAL : enum의 순서를 나타내는 숫자를 테이블에 저장
  • EnumType.STRING(권고) : enum의 이름을 테이블에 저장

@Temporal : java.util.Date, java.util.Calendar 타입으로 매핑 시 필수

  • LocalDateTime은 DB열의 TIMESTAMP 타입과 매핑되며 생략가능

엔티티와 테이블 매핑 권장 사용 방법

  • @Entity 애너테이션과 @Id 애너테이션은 필수로 추가(이름 중복 등 없으면 속성값 추가하지 않음)
  • @GeneratedValue 는 DB에서 지원하는 IDENTITY, SEQUENCE 사용
  • @Column 정보를 명시적으로 지정
  • 필드 타입이 Java의 원시타입일 경우, 생략하지 않고@Column(nullable=false)

 

4. 엔티티 간의 연관관계 매핑 : 엔티티 클래스 간의 관계를 만들어주는 것 (필드로 나타냄)

💡 연관관계는 ‘필드’ 로 나타내며, N : 1 단방향/양방향으로 고려한다. (JPA에서는 N을 기준으로 생각)
1. '다’ 필드 : @ManyToOne, @JoinColumn(name="FK_NAME")
2. (필요 시) ‘일’ 필드 : @OneToMany(mappedBy = "'다'필드의 joinColumn이름") 리스트
  • 단방향, 양방향, 일대다(1:N), 다대일(N:1), 다대다(N:N), 일대일(1:1)의 연관 관계
    • 단방향, 양방향은 JPA 개념(DB는 해당없음 - FK가 있으면 기본적으로 양 테이블간 관계가 설정됨)
    • 일대다의 관계 : 일(1)에 해당하는 클래스가 다(N)에 해당하는 객체를 참조할 수 있는 관계
    • 다대일의 관계 : 다(N)에 해당하는 클래스가 일(1)에 해당하는 객체를 참조할 수 있는 관계

다대일 단방향 매핑을 먼저 한 후에 필요한 경우, 일대다 단방향 매핑을 추가해서 양방향 연관 관계를 만드는 것이 일반적

다대일 연관관계 (N : 1) 객체 자신의 입장에서 보면 됨(객체 자신이 늘어나도, 각 필드는 1개 씩 있음)

1) ‘다대일’ 매핑관계 생성 : ’다’에 해당하는 테이블(객체)에서 ‘일’에 해당하는 테이블의 PK(객체)를 FK로 가짐

  • @ManyToOne 다대일 관계 명시
  • @JoinColumn(name="FK_NAME") 일 테이블의 외래키에 해당하는 열 이름

2) ‘일대다’매핑을 추가해서 양방향 관계를 만듦

  • @OneToMany(mappedBy = "참조 대상") -> 리스트로 표현됨
    • mappedBy의 값은 관계를 소유하고 있는 필드를 지정
    • (1) 두 객체들 간에 외래키의 역할을 하는 필드는 무엇인가? (2) 외래키의 역할을 하는 필드는 다(N)에 해당하는 클래스 안에 있다.
    • 일대다 단방향 매핑의 경우에는 mappedBy 필요 없음

다대다 연관관계 (N : N)

1 : N - N : 1로 나타낼 수 있도록 가운데 객체를 하나 더 만들어서 사용

 

@NoArgsConstructor
@Getter
@Setter
@Entity(name = "ORDERS")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long orderId;
    @Column(nullable = false, name = "LAST_MODIFIED_AT")
    private LocalDateTime modifiedAt = LocalDateTime.now();
   
    @ManyToOne   
    @JoinColumn(name = "MEMBER_ID") //Order는 Member와 N:1
    private Member member;
    
    @OneToMany(mappedBy = "order") //Order는 Recept와 1:N
    private List<Receipt> orders = new ArrayList<>();
}