
@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 Class가PK등 동일한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에서BaseEntity의PK를 포함한Field가 생성됨을 확인가능