본문 바로가기

JPA

[JPA] 필드와 컬럼 매핑

필드와 컬럼 매핑

객체의 필드와 데이터베이스의 컬럼을 매핑하는 방법에 대해 알아보겠다.

 

1. @Column

객체필드를 테이블 컬럼에 매핑한다 

 

주요 속성들

- name = String

-> 테이블 컬럼에 매핑될때의 이름을 정의한다.

 

- nullable = boolean

-> null값 허용 여부를 선택한다

 

- unique = boolean

-> 한 컬럼에 유니크 제약조건을 걸때 사용한다.

 

- length = int

-> String값에만 사용하며, 최대 길이를 설정한다.

 

예시

@Entity
@Table(name = "USER")
public class User extends CommonDate{
	
	@Id
	@GeneratedValue
	@Column(name = "ID")
	private Long id;
	
	@Column(name = "USER_NAME", nullable = false, unique = true)
	private String userName;
	
	@Column(name = "CONTRIBUTION_COUNT", nullable = false)
	private long contributionCount;
	
	@Column(name = "RANK", nullable = false)
	private long rank;
	
	public User(){}
    
}

 

2. @Enumerated

자바의 enum타입을 객체에 저장한다.

 

속성

- EnumType.STRING : enum 이름을 저장

- EnumType.ORDINAL : enum 순서를 저장

 

예시

@Enumerated(EnumType.STRING)
private TestEnum testEnum;

 

3. @Temporal (Column을 사용한다)

자바의 java.util.Date나 java.util.Calendar을 저장할때 사용한다.

하지만, 자바의 java.util.Date api는 문제점이 많아서 사용을 지양해야하는데, 자세한 이유는 아래 링크를 보자.

https://d2.naver.com/helloworld/645609

따라서, 최근엔, java.time의 LocalDate와 LocalDateTime을 주로 사용하며, 컬럼 매핑또한 @Column으로 하는걸 지향하는 편이다. 

@Column으로 필드를 매핑 해도 DB에는 date타입으로 저장된다.,

 

예시)

@MappedSuperclass
public class CommonDate{
	
	@Column(name = "LAST_MODIFIED_DATE")
	private LocalDate lastModifiedDate;
	
	public LocalDate getLastModifiedDate(){
		return this.lastModifiedDate;
	}
	
	public void setLastModifiedDate(LocalDate lastModifiedDate){
		this.lastModifiedDate = lastModifiedDate;
	}
	
}

 

4. @Lob

데이터베이스 BLOB, CLOB타입과 매핑한다. CLOB과 BLOB은 각각은 매우 긴 문자열이나, 이미지, mp3등등 구조화되지않은 매우 큰 데이터를 저장한다.

(Lob에 저장할 수 있는 데이터 최대치는 컴퓨터 용량의 크기라고 한다.)

 

@Lob
private String lobString;

@Lob
private byte[] lobByte;

 

5. @Transient

@Transient어노테이션이 있는 필드는 매핑하지 않는다.

@Transient
private String transientString;

 

6. @Access

JPA가 Entity클래스 필드에 접근하는 방식을 지정한다.

 

속성

- AccessType.FIELD : 필드에 직접 접근한다. 필드 선언이 private이여도 접근 가능하다. 

- AccessType.PROPERTY : getter와 setter를 이용해 접근한다.

 

@Access를 설정하지 않으면, @Id의 위치를 기준으로 접근 방식이 결정된다.

 

예시) 

@Entity
@Table(name = "ACCESS_CLASS")
@Access(AccessType.PROPERTY)
public class AccessClass{
    
    /.../
    
    @Id
    public String getId(){
        return this.id;
    }
    
    @Column
    public String getDate(){
        return this.date;
    }
}

 

7. 임베디드 타입

@Entity
public class TestEntity{
    ...
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="string", column=@Column(name = "IM_STRING")),
        @AttributeOverride(name="integer", column=@Column(name="IM_INTEGER"))
    })
    private TestEmb testEmb;
    ...
}

@Embeddable
public class TestEmb{
    ...
    private String string;
    private Integer integer;
   
    @Column(name = "IM_LOB")
    @Lob
    private String lob;
    ...
}

임베디드 타입은 외부 클래스를 '값 타입'(int, string...)로써 활용하게 해준다.

 

위 코드를 보자.

값 타입으로 '사용될' 클래스에 @Embeddable 어노테이션을 작성하고, 값 타입을 '사용할' 클래스안의 필드 메소드에 @Embedded를 작성하면된다.

 

값 타입의 안에는 @Column, @Lob등과 같이 컬럼 매핑을 직접 정의할수있으며, 필요시 @AttributeOverride로 속성을 재 정의 할수있다.

자세한 내용은 위의 코드를 참조하자.

 

이 임베디드 타입은 '값타입'의 범주 안에 포함된다. 다시말해, 값 타입인 Integer, String등의 특징을 그대로 가져와야하는데, 특징으로는 아래와 같다.

 

1. 서로 다른 주솟값, 같은 값을 갖고있는 값 타입은 비교시 동일해야한다. 즉, 값 타입은 동등성(equals) 비교로 비교해야한다.

 

2. 값 타입은 불변객체 이여야한다. 따라서, setter메소드를 만들지 않는다. 이는, 객체의 공유와 관련이 있는데, 만일 값 타입을 서로 다른 엔티티가 공유해서 사용한다면, 하나의 엔티티의 값 타입이 수정되었을때, 예상치못한 결과가 발생할수 있다.

값 타입을 불변으로 만들라는것은 안전을 위한 하나의 제약사항이다. 따라서, 불변으로 만들고 싶지 않다면, 엔티티끼리 공유하지않도록 복사해서 사용해야한다.

 

값 타입을 컬렉션에 보관하는 방법

@Entity
public class TestEntity{
    ...
    @Id
    @GeneratedValue
    @Column(name = "TEST_ENTITY_ID")
    private Long id
    
    @ElementCollection
    @CollectionTable(
    name = "TESTEMB", joinColumns = @JoinColumn(name="TEST_ENTITY_ID")
    )
    private List<TestEmb> testEmbs;
    ...
}

@Embeddable
public class TestEmb{
    ...
    private String string;
    private Integer integer;
   
    @Column(name = "IM_LOB")
    @Lob
    private String lob;
    ...
}

값 타입을 컬렉션에 보관하기 위해선, @ElementCollection과 @CollectionTable을 사용한다. 

@CollectionTable의 name속성에는 값타입에 해당하는 엔티티 이름을 작성하고, joinColumns에는 값 타입과 매핑할 엔티티의 ID명을 작성한다.

 

또한, 값 컬렉션은 "다"를 보관하므로 느린 로딩 Lazy를 기본값으로 갖고있다.