JPA - 각 Entity Class가 공통으로 가지는 Field 추상화하기 : @MappedSuperclass

TopOfTheHead·2025년 11월 11일

Spring JPA

목록 보기
2/10
post-thumbnail

@MappedSuperclass : jakarta.persistence.MappedSuperclass
JPA에서 Entity가 아니면서 자식 Entity Class에게 공통Field만 물려주는 용도의 부모 클래스를 정의 시 선언하는 어노테이션
▶ 주로 모든 Entity Class가 공통으로 가지는 Field ( ID, 생성일자, 추상일자 등 )를 한곳으로 모아서 추상화 시 유용하게 사용

。주로 Entity Class가 공통으로 가지는 field추상화하는 추상클래스에 선언하여 활용
▶ 각 Entity Class는 해당 추상클래스를 상속하여 공통으로 가지는 field를 상속

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseEntity {
	@Id
	@UuidGenerator
	@Column(name = "id", nullable = false, updatable = false)
	@JsonProperty(access = JsonProperty.Access.READ_ONLY)
	protected UUID id;
	@CreatedDate
	@Column(name = "created_at", nullable = false, updatable = false)
	@JsonProperty(access = JsonProperty.Access.READ_ONLY)
	protected Instant createdAt;
	@LastModifiedDate
	@Column(name = "updated_at", nullable = false, updatable = false)
	@JsonProperty(access = JsonProperty.Access.READ_ONLY)
	protected Instant updatedAt;
}

。 모든 Entity Class에서 공통으로 공유하는 ID, 생성일, 수정일을 한곳으로 모아둠
자식 Entity 클래스상속하여 해당 Field를 사용

@CreatedDate, @LastModifiedDate를 통해 생성일, 수정일을 자동 설정 시 , 선언된 Field@EntityListeners(AuditingEntityListener.class)를 선언하고, 진입점 클래스@EnableJpaAuditing를 추가 선언

Entity ClassPK 등 동일한 Field를 가지고 있는 경우 중복해서 구현한는 것 보다 추상클래스추상화해서 상속하는것이 용이
。다음처럼 VO 역할과 동시에 Entity 클래스 역할을 동시 수행하는 클래스가 존재.

	@Id
	@GeneratedValue(strategy= GenerationType.IDENTITY)
	protected Long id;
	@CreatedDate
	@Column(name="CREATEDAT", nullable = false, updatable = false)
	@JsonProperty(access = JsonProperty.Access.READ_ONLY)
	protected Instant createdAt;
	@LastModifiedDate
	@Column(name="UPDATEDAT" , nullable = false)
	@JsonProperty(access = JsonProperty.Access.READ_ONLY)
	protected Instant updatedAt;

▶ 해당 부분이 공통적으로 겹치는 것을 확인가능

리팩토링

  • ProductEntity
@Getter
@Entity
@NoArgsConstructor
@Table(name= "Product")
public class ProductEntity {
	@Id
	@GeneratedValue(strategy= GenerationType.UUID)
	protected UUID id;
	@Column(name="CREATEDAT")
	protected LocalDateTime createdAt;
	@Column(name="UPDATEDAT")
	protected LocalDateTime updatedAt;
	private String name;
	private Long prive;
	private Long stock;
	@Enumerated(EnumType.STRING)
	private ProductStatus status;
	// ...
}
  • MemberEntity
@Getter
@NoArgsConstructor
@Entity
@Table(name="Member")
// 도메인 객체와 DB Entity 역할을 동시에 수행
public class MemberEntity {
	@Id
	@GeneratedValue(strategy= GenerationType.UUID)
	protected UUID id;
	@Column(name="CREATEDAT")
	protected LocalDateTime createdAt;
	@Column(name="UPDATEDAT")
	protected LocalDateTime updatedAt;
	@Column(name = "LOGINID")
	private String loginId;
	private String password;
	private String name;
	private String email;
	private String mobile;
	@Enumerated(EnumType.STRING)
	private Gender gender;
	private LocalDate birthday;
	// ...
}

리팩토링
추상클래스에 중복되는 코드를 작성한 후 상속받도록 설정
추상클래스에 정의된 field들은 향후 상속자식클래스에서 생성자를 통해 초기화

  • 추상클래스
    추상화최상위 클래스인 경우 JPA에서 부모 클래스로 인식할 수 있도록 @MappedSuperclass를 선언
@MappedSuperclass
public abstract class BaseEntity {
	@Id
	@GeneratedValue(strategy= GenerationType.UUID)
	protected UUID id;
	@Column(name="CREATEDAT")
	protected LocalDateTime createdAt;
	@Column(name="UPDATEDAT")
	protected LocalDateTime updatedAt;
}
  • MemberEntity
@Getter
@NoArgsConstructor
@Entity
@Table(name="Member")
// 도메인 객체와 DB Entity 역할을 동시에 수행
public class MemberEntity extends BaseEntity {
	@Column(name = "LOGINID")
	private String loginId;
	private String password;
	private String name;
	private String email;
	private String mobile;
	@Enumerated(EnumType.STRING)
	private Gender gender;
	private LocalDate birthday;
	//...
}
  • OrderEntity
@Entity
@Getter
@Table(name = "Orders")
public class OrderEntity extends BaseEntity {
	@Embedded
	private Receiver receiver;
	@Enumerated(EnumType.STRING)
	private OrderStatus orderStatus;
	private LocalDateTime deliveredAt;
	// 자식 Entity 이므로 외래키 Field에 @ManyToOne을 선언
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name="memberId") // DB Table의 외래키 field명 설정
	private MemberEntity member;
}


추상화 역할의 BaseEntity를 상속한 OrderEntity매핑DB Table에서 BaseEntityPK를 포함한 Field가 생성됨을 확인가능

profile
공부기록 블로그

0개의 댓글