JPA에서 엔티티는 데이터베이스에 지속될 수 있는 POJO 즉 순수 객체를 나타낸다. 엔티티는 데이터베이스 테이블을 나타내며 각 인스턴스는 한 행을 나타낸다.
학생의 데이터를 나타내는 Student라는 POJO가 있고 이를 데이터베이스에 저장하고 싶다고 가정해본다.
public class Student {
// fields, getters and setters
}
이를 위해서는 JPA가 인식할 수 있도록 엔티티를 정의해야 한다.
@Entity 어노테이션을 사용하여 정의하며 클래스 수준에서 지정해야 한다.
또한 엔티티에 인자가 없는 생성자 혹은 기본키가 있는지 확인해야 한다.
@Entity
public class Student {
// fields, getters and setters
}
엔티티 이름은 기본적으로 클래스의 이름으로 설정된다. name 요소를 사용하여 변경할 수 있다.
@Entity(name="student")
public class Student {
// fields, getters and setters
}
@Entity가 붙은 클래스는 JPA 구현체가 각자의 기능을 제공하기 위해 엔티티를 하위 클래스화를 한다. 그렇기에 final키워드를 붙여서는 안된다.
각각의 JPA엔티티는 유니크한 기본 식별키가 있어야 한다. Id어노테이션으로 기본키를 지정할 수 있다. 여러가지의 방법으로 기본키를 생성할 수 있으며 @GeneratedValue으로 지정할 수 있다.
@GeneratedValue는 strategy요소를 사용하여 네 가지 ID 생성 전략중에서 선택할 수 있으며 값은 AUTO, TABLE, SEQUENCE IDENTITY 네 가지로 설정할 수 있다.
@Entity
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
// getters and setters
}
GenerationType.AUTO로 지정한다면 JPA는 식별자를 생성하기 위해 모든 전략을 사용한다. 엔티티 필드 즉 기본키로 지정하는 필드에 어노테이션을 추가한다면 JPA는 지정한 필드를 데이터베이스의 열과 매핑하여 데이터를 관리하게 된다.
필드 접근(Field Access)이외에도, 속성 접근(Property Access)이나 혼합 접근(Mixed Acess)도 가능하다. 이는 필드와 속성 모드를 사용할 수 있도록 해준다.
대부분의 경우 데이터베이스 테이블의 이름과 엔티티의 이름은 동일하지 않다. 이러한 경우에 @Table을 사용하여 테이블 이름을 지정할 수 있다.
@Entity
@Table(name="STUDENT")
public class Student {
// fields, getters and setters
}
스키마 요소를 사용하여 스키마를 언급할 수도 있다.
@Entity
@Table(name="STUDENT", schema="SCHOOL")
public class Student {
// fields, getters and setters
}
스키마의 이름은 한 테이블 세트를 다른 테이블 세트와 구별하는 데 도움이 된다.
@Table을 사용하지 않으면 테이블 이름이 엔티티 이름이 된다.
테이블 어노테이션과 마찬가지로 Column 주석을 사용하여 테이블의 열 세부 정보를 지정할 수 있다. @Column은 이름 길이 null허용여부, 고유값등 여러가지의 속성을 지정할 수 있다.
@Entity
@Table(name="STUDENT")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="STUDENT_NAME", length=50, nullable=false, unique=false)
private String name;
// other fields, getters and setters
}
name : 컬럼의 이름을 지정한다.
length : 컬럼의 길이를 지정한다.
nullable : 열이 null을 허용하는지 여부를 지정한다.
unique : 열이 고유한 값으로 저장할 것인지를 지정한다.
@Column을 지정하지 않으면 테이블 컬럼 이름이 필드 이름이 된다.
필드를 비영속적으로 만들고 싶을 때 사용하여 필드가 유지 되지 않도록 지정한다.
예를들어 생년월일을 기준으로 학생의 나이를 계산할 수 있다. @Transient를 영령 필드에 달아본다.
@Entity
@Table(name="STUDENT")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="STUDENT_NAME", length=50, nullable=false)
private String name;
@Transient
private Integer age;
// other fields, getters and setters
}
결과적으로 해당 필드는 테이블에 매핑이 되지 않는다.
테이블에 임시의 값을 저장할 때 사용하지만 굳이 이걸 사용할 빠에는 자료구조를 사용한다.
@Entity
@Table(name="STUDENT")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="STUDENT_NAME", length=50, nullable=false, unique=false)
private String name;
@Transient
private Integer age;
@Temporal(TemporalType.DATE)
private Date birthDate;
// other fields, getters and setters
}
그러나 JPA 3.1에서는 java.time.LocalDate, java.time.LocalTime, java.time.LocalDateTime, java.time.OffsetTime 및 java.time.OffsetDateTime도 지원합니다.
Java의 열거타입은 Emun을 매핑할 때 사용한다.
public enum Gender {
MALE,
FEMALE
}
@Entity
@Table(name="STUDENT")
public class Student {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(name="STUDENT_NAME", length=50, nullable=false, unique=false)
private String name;
@Transient
private Integer age;
@Temporal(TemporalType.DATE)
private Date birthDate;
@Enumerated(EnumType.STRING)
private Gender gender;
// other fields, getters and setters
}
만약 성별을 enum의 순서로 사용한다면, @Enumerated를 지정하지 않아도 된다. 하지만 Enum의 데이터를 디비에도 유지시키고 싶은 경우 속성을 EnumType.STRING로 맞춰주면 된다. 이렇게 설정한 경우 디비에 Enum의 값이 잘 들어간다.