엔티티 생성 관련 어노테이션, 데이터 타입 정리 (PostgreSQL)

haruceki·2024년 8월 26일

JPA 3.1 이상에서 UUID로 기본키를 작성하는 방법은 다음과 같다.
이때 데이터베이스가 UUID를 지원하는지 확인해야 한다.

@NoArgsConstructor
@Entity
@Table(name = "products")
public class Product {

	@Id
    @GeneratedValue(strategy = GenerationType.UUID)
    //@Columm(columnDefinition="UUID", updatable=false, nullable=false)
    private UUID id;
    
    @Column(precision = 10, scale = 2) // 정밀도와 소수점 자리수 정의
    private BigDecimal price;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "store_id", nullable = false)
    private Store store;
    
    @Column(columnDefinition = "TEXT") // PostgreSQL의 text 타입과 매핑
    private String productDetail;
    
    ...
    
    public void addStore(Store store){
        this.store = store;
        store.getProductList().add(this);
    }
    
}

@Columm(updatable=false, nullable=false)

해당 부분은 @Id가 제공하는 기능으로 명시적인 추가를 원할때 사용한다. 이 경우 명확한 의도 표현과 다른 필드에 대한 일관성 유지가 가능하므로 선택적으로 사용하면 된다.

@Column(columnDefinition="UUID")

columnDefinition을 사용하는 경우에는 데이터베이스에서 해당 컬럼이 UUID 타입으로 명시적으로 선언하는 역할을 한다. 이 어노테이션을 통해 JPA가 자동으로 생성하는 DDL(Data Definition Language) 스크립트에서 해당 컬럼의 타입을 명확하게 지정할 수 있다. 주로 데이터베이스 타입을 지정하고 싶은 경우, 데이터베이스의 UUID 사용 호환성 체크, 스키마의 세밀한 제어를 위해 사용한다.

@Table(name = "products")

PostgreSQL에서 테이블 이름을 지정할 때, 쌍따옴표로 감싸지 않으면 대소문자 구분 없이 모두 소문자로 변환된다.
만약 테이블 이름에서 대문자를 사용하고 싶다면, 반드시 쌍따옴표로 감싸야 한다. 예를 들어, @Table(name = "\"Products\"")로 지정해야 하는데 이 경우 대소문자를 정확히 일치시켜야 한다.
대부분의 PostgreSQL 사용자와 많은 개발자들이 일관성 유지를 위해 테이블과 컬럼 이름을 소문자로만 사용하는 것을 선호한다. 이는 다른 데이터베이스와의 호환성 문제도 줄여준다.
대문자를 사용하려면 쿼리에서 쌍따옴표를 항상 사용해야 하므로 불편할 수 있다. 또한, 대소문자를 구분해야 하므로, 실수로 인해 오류가 발생할 가능성이 높다.

@NoArgsConstructor

JPA에서 @NoArgsConstructor를 사용하는 주된 이유는 다음과 같다.
1. JPA 표준: JPA 스펙에 따르면, 엔티티 클래스는 반드시 기본 생성자(매개변수가 없는 생성자)를 가져야 한다다. 이 기본 생성자는 public 또는 protected로 선언되어 있어야 하며, JPA 구현체(Hibernate 등)가 엔티티 객체를 인스턴스화할 때 사용된다.
2. 엔티티 매핑: JPA는 데이터베이스에서 조회한 데이터를 엔티티로 변환할 때 기본 생성자를 사용해 객체를 생성한 후, 필드에 값을 채운다. 만약 기본 생성자가 없다면, JPA는 엔티티를 생성할 수 없으므로 예외가 발생한다.
3. 테스트 및 프록시 객체 생성: 기본 생성자가 있으면 테스트 코드나 프록시 객체 생성 시에도 유리하다. 기본 생성자를 통해 객체를 간편하게 생성할 수 있으며, JPA의 프록시 메커니즘이 정상적으로 동작하게 된다.
외부에서 직접 호출하지 못하도록 하면서, JPA 내부적으로는 사용할 수 있도록 하려면@NoArgsConstructor(access = AccessLevel.PROTECTED) 로 사용하면 된다.

@AllArgsConstructor

JPA 엔티티에서 @AllArgsConstructor를 사용하는 것은 특정 상황에서 유용할 수 있지만 JPA 엔티티의 특성상 신중하게 사용해야 한다. 주로 엔티티와 DTO 간 변환시 또는 단위테스트에서 엔티티 객체를 빠르게 생성할 때 사용한다. 따라서 엔티티보다는 값객체(VO)나 DTO에서 더 자주 사용된다.
중요한 점은 JPA 스펙에 따라 엔티티에는 반드시 기본 생성자가 있어야 하며 이 생성자는 public 또는 protected이어야 한다. 만약 @AllArgsConstructor만 사용하면 기본 생성자가 없어서 JPA가 엔티티를 인스턴스화할 때 오류가 발생할 수 있다. 따라서 @NoArgsConstructor를 함께 사용해야 한다.

@Setter, @Getter

JPA 엔티티에서 직접 엔티티의 값을 변경하는 @Setter는 사용하지 않는다.
JPA 엔티티에서 @Getter를 사용하는 것은 데이터의 캡슐화나 필드에 직접 접근할 필요가 있을 경우, 비즈니스 로직에서 필드값을 읽어와서 처리할 필요가 있는 경우 사용된다.

BigDecimal 데이터 타입

PostgreSQL에서 numeric 또는 decimal 데이터 타입을 JPA 엔티티로 매핑할 때는, JPA의 BigDecimal 클래스를 사용하면 된다. PostgreSQL의 numeric 및 decimal 타입은 고정 소수점 숫자를 저장하며, 이와 유사한 Java 타입은 BigDecimal이다. BigDecimal은 정확한 소수점 연산을 제공하며, 금융 및 계산적인 데이터에서 자주 사용된다.

@Column(columnDefinition = "TEXT")

PostgreSQL에서 text 데이터 타입을 JPA 엔티티로 매핑할 때는, Java의 String 클래스를 사용하여 매핑하면 된다. PostgreSQL의 text 타입은 가변 길이의 문자열을 저장할 수 있으며, 이는 Java의 String 타입과 매칭된다.
PostgreSQL에서는 text 타입을 명시적으로 정의하지 않아도 String으로 자동 매핑되지만, columnDefinition을 사용하여 매핑을 명확히 할 수 있다. columnDefinition을 사용시에는 데이터베이스의 이식성을 고려해야 하며 불필요한 사용은 유연성을 잃게 할 수도 있다.

fk 컬럼에 @Column(nullable = false)

외래 키가 참조하는 기본 키 컬럼이 NOT NULL로 정의되어 있다면, 해당 외래 키 역시 NOT NULL로 설정하는 것이 일관성을 유지에 좋다.
외래 키가 기본 키가 아닌 경우지만 외래 키가 참조하는 컬럼이 NULL을 허용할 수 있는 경우에는 외래 키 컬럼 자체도 NULL을 허용할 수 있다. 하지만 외래 키가 반드시 값을 가져야 하는 경우에는 nullable = false를 명시하는 것이 좋다.

연관관계 편의 메서드

연관관계 편의 메서드는 두 엔티티 간의 관계를 설정하거나 해제할 때, 양쪽 엔티티의 상태를 일관성 있게 유지하기 위한 메서드이다. 이를 통해 한쪽 엔티티에서 관계를 설정하면, 자동으로 다른 쪽 엔티티에서도 그 관계를 설정하거나 해제할 수 있다. 양방향 연관관계인 경우 하나의 두 엔티티 중 하나의 엔티티에 메서드를 작성해 주어야하며, 주로 사용하는 @ManyToOne, @OneToOne 등 모든 관계에서 필요하다.

profile
희망도 절망도 없이 매일 코딩을 한다.

0개의 댓글