[Spring Boot] Entity (엔티티)
Entity ?
엔티티는 데이터베이스 테이블과 매핑되는 자바 클래스를 말한다.
Entity 속성 구상
질문과 답변에 대한 게시판을 생각했을 때, 최소한으로 가지고 있어야할 요소들이 있다.
질문 : 질문을 구분할 수 있는 고유 id 혹은 번호 , 질문의 제목, 질문의 내용, 질문작성일시 등
답변 : 답변을 구분할 수 있는 고유 id 혹은 번호, 답변한 질문을 구분할 수 있는 id 혹은 번호, 답변의 내용, 답변작성일시 등
위의 내용을 바탕으로 표로 정리를 해보면 다음과 같다.
Question (질문)
속성명 | 설명 |
id | 질문의 고유값 |
subject | 질문의 제목 |
content | 질문의 내용 |
create_date | 질문작성일시 |
Answer(답변)
속성명 | 설명 |
id | 답변의 고유값 |
question | 답변을한 질문의 고유값 |
content | 답변의 내용 |
create_date | 답변작성일시 |
위 표를 참고하여 Entity를 작성한다.
Question.java
package com.myspringboot.ssh;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.springframework.data.annotation.CreatedDate;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity //엔티티 선언 어노테이션 (JPA에서 엔티티로 인식한다)
public class Question {
@Id // 기본 키로 지정
@GeneratedValue(strategy = GenerationType.IDENTITY) // 데이터를 저장할 때 해당 속성에 값을 따로 세팅하지 않아도 1씩 자동으로 증가하여 저장
private Integer id;
//엔티티의 속성은 테이블의 컬럼명과 일치하는데 컬럼의 세부 설정을 위해 @Column 애너테이션을 사용
//테이블 컬럼으로 인식하고 싶지 않은 경우에만 @Transient 애너테이션을 사용
@Column(length=200)
private String subject;
//엔티티의 속성은 테이블의 컬럼명과 일치하는데 컬럼의 세부 설정을 위해 @Column 애너테이션을 사용
//테이블 컬럼으로 인식하고 싶지 않은 경우에만 @Transient 애너테이션을 사용
@Column(columnDefinition = "TEXT") // columnDefinition = "TEXT"는 글자 수를 제한할 수 없는 경우에 사용
private String content;
@CreatedDate
private LocalDateTime createDate;
}
테이블의 컬럼명
위의 Question 엔티티에서 작성일시에 해당하는 createDate 속성의 실제 테이블의 컬럼명은 create_date가 된다. 즉 createDate처럼 대소문자 형태의 카멜케이스(Camel Case) 이름은 create_date 처럼 모두 소문자로 변경되고 언더바(
_)로 단어가 구분되어 실제 테이블 컬럼명이 된다.
Answer.java
package com.myspringboot.ssh;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.springframework.data.annotation.CreatedDate;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
public class Answer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(columnDefinition = "TEXT")
private String content;
@CreatedDate
private LocalDateTime createDate;
@ManyToOne
private Question question;
}
답변은 하나의 질문에 여러개가 달릴 수 있는 구조이다. 따라서 답변은 Many(많은 것)가 되고 질문은 One(하나)이 된다.
따라서 @ManyToOne은 N:1 관계라고 할 수 있다.
이렇게 @ManyToOne 애너테이션을 설정하면 Answer 엔티티의 question 속성과 Question 엔티티가 서로 연결된다.
(실제 데이터베이스에서는 ForeignKey 관계가 생성된다.)
- @ManyToOne은 부모 자식 관계를 갖는 구조에서 사용한다. 여기서 부모는 Question, 자식은 Answer라고 할 수 있다.
추가적으로 답변과 질문이 N:1의 관계라면 질문과 답변은 1:N의 관계라고 할 수 있다.
Question 엔티티에서 Answer 엔티티를 참조하기 위해서는 @ManyToOne이 아닌 @OneToMany애너테이션을 사용한다. Question 하나에 Answer는 여러개이므로 Question 엔티티에 추가할 답변의 속성은 List 형태로 구성해야 한다.
Question.java 소스추가
package com.myspringboot.ssh;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import org.springframework.data.annotation.CreatedDate;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity //엔티티 선언 어노테이션 (JPA에서 엔티티로 인식한다)
public class Question {
@Id // 기본 키로 지정
@GeneratedValue(strategy = GenerationType.IDENTITY) // 데이터를 저장할 때 해당 속성에 값을 따로 세팅하지 않아도 1씩 자동으로 증가하여 저장
private Integer id;
//엔티티의 속성은 테이블의 컬럼명과 일치하는데 컬럼의 세부 설정을 위해 @Column 애너테이션을 사용
//테이블 컬럼으로 인식하고 싶지 않은 경우에만 @Transient 애너테이션을 사용
@Column(length=200)
private String subject;
//엔티티의 속성은 테이블의 컬럼명과 일치하는데 컬럼의 세부 설정을 위해 @Column 애너테이션을 사용
//테이블 컬럼으로 인식하고 싶지 않은 경우에만 @Transient 애너테이션을 사용
@Column(columnDefinition = "TEXT") // columnDefinition = "TEXT"는 글자 수를 제한할 수 없는 경우에 사용
private String content;
@CreatedDate
private LocalDateTime createDate;
@OneToMany(mappedBy = "question", cascade = CascadeType.REMOVE)
private List<Answer> answerList;
}
질문 객체(예:question)에서 답변을 참조하려면 question.getAnswerList()를 호출하면 된다. @OneToMany 애너테이션에 사용된 mappedBy는 참조 엔티티의 속성명을 의미한다.
즉, Answer 엔티티에서 Question 엔티티를 참조한 속성명 question을 mappedBy에 전달해야 한다.
CascadeType.REMOVE
질문 하나에는 여러개의 답변이 작성될 수 있다. 이때 질문을 삭제하면 그에 달린 답변들도 모두 함께 삭제하기 위해서 @OneToMany의 속성으로 cascade = CascadeType.REMOVE를 사용했다.
참고: https://www.baeldung.com/jpa-cascade-types
엔티티를 작성하고 H2의 콘솔을 보면 테이블이 생성된 것을 확인할 수 있다.
출처 : 점프 투 스프링부트