상속을 이용해 Entity 구성하기
서론
JPA를 이용해 프로젝트를 구성해보거나 실습을 해보았다면, 당연하게도 Entity를 만들어 사용해본 적이 있을 것이다. 그런데, 이 Entity, 낯선 annotation이 덕지덕지 붙어있어서 그렇지, 본질적으로는 자바 객체이다. 즉, 객체 지향 프로그래밍의 가장 큰 특징 중 하나인, 상속과 다형성을 활용한 구성이 가능할 수밖에 없다.
공식 문서를 읽어보기 전까지는 상속을 이용해 Entity를 구성해보겠다는 생각조차 한 적이 없었다. 그래서, 이번 글에서는 추상/일반 클래스를 상속해 Entity를 구성하는 법에 대해 간단하게 정리해보겠다.
Entity Inheritance
Entity는 Entity가 아닌 클래스, Entity인 클래스 모두 상속할 수 있다. 또 상속에 사용되는 Entity 클래스는 추상 클래스일수도, 일반 클래스일수도 있다. 각각의 경우에 따라 예시와 함께 개념을 알아보자.
Abstract Entities
우선, 부모 클래스가 추상 Entity 클래스인 경우부터 살펴보자. 추상 Entity는 일반 Entity와 비슷하지만, 인스턴스화되지 않는다. 그와 별개로 쿼리의 대상이 될 수는 있다. 부모 클래스가 되는 추상 Entity 클래스가 쿼리 대상에 포함되면, 그 쿼리는 해당 추상 클래스를 상속한 모든 Entity에 대해 시행된다.
@Entity
public abstract class Employee {
@Id
protected Integer employeeId;
...
}
@Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
...
}
@Entity
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
}
위와 같이 상속 관계가 이루어졌다고 치면, abstract class Employee가 쿼리의 대상이 된다면, FullTimeEmployee와 PartTimeEmployee가 쿼리의 대상으로 선정된다는 뜻이다.
쿼리 대상이 되지 않는 super class
만일 쿼리의 대상으로 삼을 생각이 없고, 그저 반복되는 일정한 Entity의 속성을 여러 Entity에게 부여하고 싶다면, @MappedSuperclass annotation을 이용해 클래스를 구성하면 된다.
@MappedSuperclass
public class Employee {
@Id
protected Integer employeeId;
...
}
@Entity
public class FullTimeEmployee extends Employee {
protected Integer salary;
...
}
@Entity
public class PartTimeEmployee extends Employee {
protected Float hourlyWage;
...
}
@MappedSuperclass annotation이 붙은 클래스, Employee는 다음과 같은 특징을 가지고 있다.
- Entity의 속성을 가진 필드가 있다. (@Id annotation이 붙은 employeeId 필드 존재)
- 하지만 Entity는 아니다.
@Id annotation은 Entity 클래스에서 해당 속성이 PK임을 나타내기 위해 사용하는 annotation이다. 때문에 Entity class 내부에 존재해야 하는데, 상속용 부모 클래스가 Entity로서의 속성을 전혀 가질 필요가 없을 수 있다. 그런 경우 @MappedSuperclass를 이용해 클래스를 구성하면, EntityManager나 Query의 대상이 전혀 되지 않는 부모 클래스를 만들 수 있다.
일반 클래스의 상속
평범하게, 부모 클래스가 일반 클래스인 Entity도 구성할 수 있다. 이 경우 부모 클래스에서 상속된 모든 state는 영속화의 대상이 되지 않는다. 또, 부모 클래스에서 Entity의 mapping, relationship과 관련된 annotation을 작성했다 해도 모두 무시된다. (그런 내용을 작성해야 한다면, 위에 나왔던 @MappedSuperclass를 이용하자.)