@MappedSuperclass
이번 시간에는 @MappedSuperclass라는 어노테이션에 대해서 알아보겠다!!
별 거 없다!! 그런데 유용하다!! 편하게 보자~~
우리가 관리하고 있는 어플리케이션에서 테이블에 데이터를 누가 언제 등록했고 수정했는지 관리해야 한다고 해보자!
그런데 이 관리를 특정 테이블이 아닌 거의 모든 테이블에서 해야 한다!
그러면 우리는 각 Entity마다 컬럼을 지정해야 한다..
Student.java
package hellojpa;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Data
public class Student {
@Id @GeneratedValue
private Long id;
private String name;
private int age;
@ManyToOne
@JoinColumn(name = "CLUB_ID", insertable = false, updatable = false)
private Club club;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
Locker locker;
@OneToMany(mappedBy = "student")
private List<StudentSubject> studentSubjects = new ArrayList<>();
private String creator;
private LocalDateTime createdAt;
private String modifier;
private LocalDateTime lastModifiedAt;
void addStudentSubject(StudentSubject studentSubject) {
studentSubject.setStudent(this);
studentSubjects.add(studentSubject);
}
}
Club.java
package hellojpa;
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Data
public class Club {
@Id @GeneratedValue
@Column(name = "CLUB_ID")
private Long id;
private String name;
private String description;
@OneToMany
@JoinColumn(name = "CLUB_ID")
private List<Student> students = new ArrayList<>();
private String creator;
private LocalDateTime createdAt;
private String modifier;
private LocalDateTime lastModifiedAt;
}
지금 Club과 Student Entity에 공통적으로 creator, createdAt, modifier, lastModifiedAt까지 4개의 속성이 겹친다.
이 속성들은 누가 언제 데이터를 생성했고, 수정했는지 관리하는 역할을 한다.
(지금은 Entity 2개라 적어보이지만, 나중에 수십 개의 테이블을 이렇게 관리해야 한다면 수많은 중복이 생길 것이다.)
이럴 때 중복을 제거하기 위해 사용하는 어노테이션이 `@MappedSuperclass`이다.
@MappedSuperclass
package hellojpa;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@Data
@MappedSuperclass
public abstract class BaseEntity {
@Column(nullable = false)
private String creator;
@CreationTimestamp
private LocalDateTime createdAt;
private String modifier;
private LocalDateTime lastModifiedAt;
}
사용방법은 간단하다. 공통 속성들을 하나의 클래스에 모아서 정의해놓는다!
그리고 공통속성들을 모아놓은 class에 @MappedSuperclass 어노테이션을 달아주면 완성이다.
또한 @MappedSuperclass의 class에는 Entity의 필드에 사용하는 어노테이션들을 그대로 사용할 수 있다.
이제 다른 Entity들이 상속받기만 하면 정의된 공통속성들을 가질 수 있다.
지금 보면 기반 클래스가 추상클래스로 선언되어 있다.
기반 클래스는 공통속성을 관리하기 위한 역할만을 하고,
Entity는 아니기때문에 단독으로 사용하지 못하도록 추상클래스로 만드는 것이다.
하지만 추상 클래스가 아니어도 동작하는데에는 지장이 없다.
Student.java
package hellojpa;
import lombok.Data;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Data
public class Student extends BaseEntity {
@Id @GeneratedValue
private Long id;
private String name;
private int age;
@ManyToOne
@JoinColumn(name = "CLUB_ID", insertable = false, updatable = false)
private Club club;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
Locker locker;
@OneToMany(mappedBy = "student")
private List<StudentSubject> studentSubjects = new ArrayList<>();
void addStudentSubject(StudentSubject studentSubject) {
studentSubject.setStudent(this);
studentSubjects.add(studentSubject);
}
}
Club.java
package hellojpa;
import lombok.Data;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Data
public class Club extends BaseEntity {
@Id @GeneratedValue
@Column(name = "CLUB_ID")
private Long id;
private String name;
private String description;
@OneToMany
@JoinColumn(name = "CLUB_ID")
private List<Student> students = new ArrayList<>();
}
Student와 Club class가 @MappedSuperclass 어노테이션을 가진 BaseEntity를 상속받았다.
4개의 공통 속성(creator, createdAt, modifier, lastModifiedAt)도 상속되었고,
이제는 각 Entity마다 공통 속성들을 선언해주지 않아도 된다.
JpaMain.java
package hellojpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class JpaMain {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// programming club 생성
Club club = new Club();
club.setName("programming");
club.setDescription("즐거운 프로그래밍?");
club.setCreator("code-mania");
em.persist(club);
// code-mania student 생성
Student student = new Student();
student.setName("code-mania");
student.setClub(club);
student.setCreator("code-mania");
em.persist(student);
tx.commit();
} catch (Exception e) {
tx.rollback();
e.printStackTrace();
} finally {
em.close();
}
em.close();
emf.close();
}
}
데이터가 DB에 매우 잘 들어가고 있다.
(CREATEDDATE같은 경우 setter를 통해 지정한 것이 아니라 @CreationTimestamp에 의해 알아서 값이 세팅되었다.)