[BE/1주차] JPA Annotation

Rare·2020년 7월 31일
1

backend

목록 보기
1/6
post-thumbnail

프로젝트를 만들면서 필요한 부분을 정리하고 있습니다.
모호하거나, 잘못된 부분이 있으면 댓글로 남겨주세요! 감사합니다 :)

@MappedSuperclass


개요

  • 객체의 입장에서, 공통 맵핑 정보를 나타내고 싶을 때, class 위에 기재함
  • 위의 그림에서 보면, id, name 이 반복 되므로, BaseEntity 라는 클래스로 따로 만들어서 이 클래스 내부 변수로 만들어준다음에,
  • Member, Seller 가 해당 클래스를 상속받는 형식으로 진행된다.

코드

  • 가정 : 생성자, 생성시간, 수정한 사람을 모든 엔티티들에서 공통으로 가진다.
  • BaseEntity로 정의한다.
@Getter
@Setter
@MappedSuperclass
public abstract class BaseEntity {

    private String createdBy;

    private LocalDateTime createdDate;

    private String lastModifiedBy;

    private LocalDateTime lastModifiedDate;
}
  • 이 클래스는 Entity가 아니라, 맵핑 정보만 가지고 있는 SuperClass란 의미로 @MappedSuperclass로 선언한다.
  • Member, Team
@Entity
public class Member extends BaseEntity {
    //...
}

@Entity
public class Team extends BaseEntity {
    //...
}
  • BaseEntity를 상속(extends) 받았다.

  • 위와 같이 설정했을 때, 만들어지는 DDL(Data Definition Language)

Hibernate: 
    create table Member (
       id bigint generated by default as identity,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        age integer,
        description clob,
        roleType varchar(255),
        name varchar(255),
        locker_id bigint,
        team_id bigint,
        primary key (id)
    )
Hibernate: 
    create table Team (
       id bigint generated by default as identity,
        createdBy varchar(255),
        createdDate timestamp,
        lastModifiedBy varchar(255),
        lastModifiedDate timestamp,
        name varchar(255),
        primary key (id)
    )
  • BaseEntity에 정의된 변수들이 컬럼으로 선언되는 것을 볼 수 있음.

@AttributeOverride


개요

  • 상속받은 자식 객체에서, 정의되어있는 변수명(createdDate) 말고, 다른 변수명(publishedAt)으로 바꾸고 싶으면?
  • 해당 annotation을 이용한다.
@Entity
@AttributeOverride(name = "createdDate", column = @Column(name = "publishedAt"))
public class Member extends BaseEntity { 
    //...
}

정리

  • @MappedSuperclass가 선언되어 있는 클래스는 Entity가 아니다!
    • 즉 테이블로 매핑되지 않는다.
    • 그러면 JPQL을 사용할 수 없음!
  • 부모클래스(BaseEntity)는 상속 받는 자식 클래스(Member, Team)에 맵핑 정보들만 제공한다.
  • 부모 클래스는 추상 클래스 만들어서 사용하는 것이 권장된다.
    • 왜? 직접적으로 생성할 일이 없으므로...
  • @MappedSuperclass가 선언되어 있는 클래스 엔티티들이 공통적으로 사용하는 맵핑 정보를 모으는 클래스이다.

@Embeddable, @Embedded


개요

  • 의미는 내재되어있는 이라는 의미.
  • 새로운 값 타입 을 직접 정의해서 사용할 수 있도록 해준다
  • @Embeddable은 값 타입 정의하는 클래스에 사용되고,
    • 기본 생성자 필수!
  • @Embedded는 사용되는 엔티티의 내부 변수 위에 기재된다.

코드

1. 임베디드 타입을 사용하지 않았을 때

@Entity
public class Member {
  
  @Id @GeneratedValue
  private Long id;
  private String name;
  
  // 근무 기간
  @Temporal(TemporalType.DATE)
  Date startDate;
  @Temporal(TemporalType.DATE)
  Date endDate;
  
  // 집 주소 표현
  private String city;
  private String street;
  private String zipcode;
  
  // ...
}
  • 회원 엔티티는 id name, 근무기간, 집주소를 가진다
    • 이렇게 간단하게 이야기 할 수 있지만,
    • 실질적으로 회원 엔티티가 가지고 있는 변수들은 많다!
    • 이걸 줄일 수 없을까?

2. 임베디드 타입을 사용할 때

@Entity
public class Member {
  
  @Id @GeneratedVAlue
  private Long id;
  private String name;
  
  @Embedded //실제 사용되는 엔티티 변수 위에
  private Period workPeriod;	
  
  @Embedded
  private Address homeAddress;
}

@Embeddable //값 타입의 class
public class Period {
  
  @Temporal(TemporalType.DATE)
  private Date startDate;
  @Temporal(TemporalType.Date)
  private Date endDate;
  
  // ...
}

@Embeddable
public class Address {
  
  @Column(name="city") // 매핑할 컬럼 정의 가능
  private String city;
  private String street;
  private String zipcode;
  
  // ...
}

  • 임베디드 타입을 포함한, 모든 값 타입은 이를 사용하고 있는 Entity의 생명 주기에 의존하게 되므로, 이러한 관계를 UML로 표현 하면 위와 같고,
  • 이를 Composition 컴포지션 관계라 합니다.

정리

  • Embdded는 사용되는 쪽에, Embddable 값 타입 클래스를 정의 할때 사용한다
  • 객체와 테이블을 아주 세밀하게 맵핑하는 것이 가능하다
    • 무슨 말일까?
    • 아마도 객체 : 테이블 = 1:1 이 아닌, 객체는 엄청나게 세분화 하면서 테이블은 하나가 되도록 만들 수 있다는 말인듯.
    • 그래서 잘 설계한 ORM Application은 맵핑한 테이블 수보다 , 클래스 수가 많다 —> 라는 말이 나오지 않았을까?
  • 사용 장점
    1. 재사용이 편리하고,
    2. 객체간의 높은 응집도를 가지는 구조를 만들 수 있음.

@EntityListeners


개요

  • Entity의 데이터 변경을 알려줄 때 사용하는듯
  • Entity 를 DB에 적용하기 이전에, Call back을 요청할 수 있는 annotation

코드

@EntityListeners(DataDtoListener.class) // {} 를 통해서, 복수의 리스너를 등록할 수 있음
@Entity
public class DataDto() {
   
   @Id
   private long id;
   
   //...
}

public class DataDtoListener {
    
    @PostLoad
    public void postLoad(DataDto dto) {
        log.info("post load: {}", dto);
    }
    
    @PrePersist
    public void prePersist(DataDto dto) {
        log.info("pre persist: {}", dto);
    }
    
    @PostPersist
    public void postPersist(DataDto dto) {
        log.info("post persist: {}", dto);
    }
    
    @PreUpdate
    public void preUpdate(DataDto dto) {
        log.info("pre update: {}", dto);
    }
    
    @PostUpdate
    public void postUpdate(DataDto dto) {
        log.info("post update: {}", dto);
    }
    
    @PreRemove
    public void preRemove(DataDto dto) {
        log.info("pre remove: {}", dto);
    }
    
    @PostRemove
    public void postRemove(DataDto dto) {
        log.info("post remove: {}", dto);
    }
}
  • EntityListener 클래스에 적용한 이벤트는 다음 시점에 호출된다
    • @PostLoad : 해당 엔티티를 새로 불러오거나 refresh 한 이후
    • @PrePersist : 해당 엔티티를 저장하기 이전
    • @PostPersist: 해당 엔티티를 저장한 이후
    • @PreUpdate : 해당 엔티티를 업데이트 하기 이전
    • @PostUpdate : 해당 엔티티를 업데이트 한 이후
    • @PreRemove : 해당 엔티티를 삭제하기 이전
    • @PostRemove : 해당 엔티티를 삭제한 이후

AuditingEntityListener

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {

  @CreatedDate
  private LocalDateTime createdTimeAt;

}
  • Auditing?
    • 감시하다라는 뜻
  • Entity를 영속성 컨테스트에 저장하거나, 조회를 수정한 후 update 하는 경우에 자동으로 auditor, time을 맵핑하여 데이터 베이스에 넣도록 도와준다.
  • 스프링 부트의 엔트리 포인트인 실행 클래스에 @EnableJpaAuditing 을 적용하여 JPA Auditing을 활성화 해야한다.

정리

  • EntityListener클래스를 만들어서 어떠한 Entity에 붙이면, 특정 상황에 리스너 클래스에 있는 콜백 메서드를 사용할 수 있도록 해줌.
  • AuditingEntityListener 클래스의 경우, 붙여놓으면, Entity가 생성, 수정등의 액션에서 특정 컬럼(수정시간, 생성시간, 생성자, 수정자)에 대해 자동으로 DB에 맵핑되도록 도와준다.

@CreateDate


개요

  • Entity 생성, 수정시 특정 필드를 자동으로 데이터베이스에 맵핑해주기 위해 사용함
  • Auditing 기능을 사용하려면, 위의 어노테이션을 사용해야한다.
    • @EnableJpaAuditing 이 필수적으로 SpringApplication 시작에 있어야 하고
  • Spring Data JPA에서 사용할 때는 이를 사용하는게 좋을듯

정리


참고

@MappedSuperclass, @AttributeOverride

@Embeddable, @Embedded

@EntityListeners, AuditingEntityListener

참고사이트

profile
블로그 서비스 ‘레어’ 기술 블로그

0개의 댓글