당니의 개발자 스토리

Mapped Superclass - 매핑 정보 상속 본문

스프링/자바 ORM 표준 JPA 프로그래밍 - 기본편

Mapped Superclass - 매핑 정보 상속

clainy 2024. 8. 22. 19:36

Mapped Superclass - 매핑 정보 상속


자 이번에는 @MappedSuperclass 라는 것에 대해서 설명을 해드리겠습니다.

일단 이거는 상속관계 맵핑이랑 별로 관계가 없습니다.
자 얘가 뭐냐면,


이렇게 예를 들어 볼게요. 예를 들어서 상속 관계를 맵핑하려면 이전 시간에 배웠던 그거대로 해야 되거든요. 테이블까지 되게 고민해야 되잖아요. 이건 그런 게 아니고 그냥 진짜 단순하게 객체 입장에서 id랑 name이라는 필드가 계속 나오는 거예요. id랑 name이라는 필드가 Member에도 나오고 Seller에도 나오고 계속 나오는 거예요. 그러니까 맨날 객체 클래스를 만들 때마다 막 id랑 name을 넣어야되는 게 귀찮다보니, 부모 클래스에 두고 속성만 상속해서 사용하고 싶죠.

아래 그림을 보면, @MappedSuperclass는 DB 자체는 그냥 다 따로 쓰는 거예요. 이전 시간에 했던 상속관계 맵핑에서는 테이블마다 생긴 게 달랐지만 DB의 슈퍼타입, 서브타입으로 모델링 했었죠. @MappedSuperclass는 다릅니다. 상속 개념과 달라요.

지금 보시면은 MemberSeller가 있는데 Member에도 id, name이 있고 Seller에도 id, name이 있는 거예요. DB는 Member와 Seller가 아무런 연관도 없고 완전히 다른데 객체 입장에서는 속성만 상속받아서 쓰고 싶은 거예요. 그래서 뭔가 공통 맵핑 정보가 필요할 때, 이 귀찮음을 좀 줄이자고자 할 때 쓰는 겁니다.
예시를 한번 보여드릴게요.

이렇게 해볼까요. 지금 우리 애플리케이션은 모든 곳에 등록, 수정. 누가 등록했고 몇 시에 등록했다. 라는 정보가 있어야 돼요. 그리고 누가 수정했고 몇시에 수정했어. 라는 정보도 항상 있어야 된다고 하는 거예요. 모든 테이블에.
만약에 dba 분이 이렇게 룰을 잡았으면 저희는 무조건 따라갈 수 밖에 없어요.
그러면 먼저 Member에다가 집어넣는다고 하면,

이렇게 집어넣겠죠. 이거를 막 DBA가 갑자기 나타나서 '아 이거 당연히 운영하려면 이거 다 까셔야죠' 라고 해요.

그러면 모든 테이블에 복붙해야겠죠. Member에 넣은 걸 복사해서 Team에다가도 복붙하고. 그런데 개발자 입장에서는 중복핱기도 하고 좀 거시기 하잖아요. 이 속성만 상속 받아서 쓰고 싶은데.
그게 이제 되는게 Mapped Superclass 입니다.

자 BaseEntity 라고 만들게요.

그 다음에 BaseEntity에다가 이걸 집어 넣는거에요.

이렇게 넣은 다음, Getter, Setter는 다 넣고나서

extends BaseEntity 이렇게 해주면 됩니다. 그 다음에 Member에다가도 똑같이 해주면 됩니다.

물론 그냥 해서는 실행 안되고요. @MappedSuperclass 어노테이션을 넣어주셔야 됩니다. BaseEntity는 이제 맵핑 정보만 받는 부모 클래스, 슈퍼 클래스 라고 보시면 돼요.
그리고 그 다음에 이제 JPA에서 로직을 짤 때

이렇게 해서 넣고 돌리면,

create table 보면 이 4가지 생겼죠? createdBy, createdDate 이거 쭉쭉 생겼죠? 그 다음에 Team에도 상속받았으니까 Team을 보면,

이게 있죠.
자 결국 이 Mapped Superclass 라는 건 뭐냐면 뭐 어려운 게 아니라 그냥 상속관계 맵핑, 이런 게 전혀 아니고

그냥 여기 있는 속성을 같이 쓰고 싶어 라고 할 때 쓰는 거예요.

그리고 뭐 이런 것도 됩니다. @Column 해가지고 내가 예를 들어서 createdBy를 안 하고 그냥 한국 스타일로 ISERT_MEMBER 라고 바꿔볼게요.

그리고 lastModifiedBy에도 UPDATE_MEMBER 라고 바꿀게요. 그러고 나서, 실행해보면

보시면 Team 테이블에도 INSERT_MEMBER로 바뀌었고 Member 테이블에도 INSERT_MEMBER로 바뀌었죠.
이런 식으로 뭔가 전체적으로 공통적으로 사용할 속성에는 Mapped Superclass를 사용하시면 됩니다.

그리고 이제 참고로 나중에 JPA 계속 공부해 보시면 아시겠지만 createdDatelastModifiedDate 같은 이런 정보들은 다 자동화할 수 있습니다.

내가 이렇게 setCreatedBy, setCreatedDate 해서 직접 넣어주는게 아니라, Admin에 현재 로그인 되어있는 세션 정보를 읽어와서 이름을 넣어주거나 하는 거 다 JPA에서 Event 라는 기능으로 다 할 수가 있고 뒤에 스프링 데이터 JPA까지 합치면 굉장히 심플하게 그런 것들을 Annotation이 제공이 되거든요. 그런 걸로 되게 심플하게 시간 정도는 그냥 다 넣을 수 있습니다.
그래서 기본적으로 저도 이런 BaseEntity 같은 거를 만들고 깔아서 프로젝트를 해요.

사실 이거는 다 있어야죠. 진짜 변경이 안 되는 테이블이 있을 수 있어요. Immutable는 테이블 이런 거 빼고는 다 기본적으로 깔아야죠. 안그럼 운영을 할 수가 없잖아요. 나중에 누가 등록했는지 누가 수정했는지 정도는 있어야 되니까요. 그래서 보통 다 깔죠.

자 그래서 공통의 맵핑 정보가 필요할 때 사용한다. 라고 보시면 되구요.

얘는 이제 상속 관계 맵핑이 아닙니다. 이거를 절대 헷갈리시면 안됩니다. 그 다음에 얘는 엔티티가 아니에요. 그래서 @MappedSuperclass 라고 하는 애는 테이블이랑 맵핑이 안됩니다. 무슨 말이냐면,

BaseEntity라는 게 지금 생성된 게 없어요. create 테이블 보시면 없죠.


그냥 속성만 내려주는 애고 엔티티가 아닙니다. 그래서 부모 클래스를 상속받는 자식 클래스에 맵핑 정보만 제공합니다. 그래서 이 @MappedSuperclass 타입으로는 조회랑 검색이 안됩니다.

예를 들어서 em.find()를 가지고 부모 타입으로 조회가 안된다는 거예요. 저번 시간같이 상속관계에서는 Item 타입으로 제가 조회했던 거 보여드렸죠. 얘는 BaseEntity.class 해서 id로 조회하고 이런 거는 안되는 겁니다. 오류 납니다.


그리고 이제 이게 되게 중요한데요. 직접 생성해서 사용할 일이 없으므로 추상 클래스로 쓰시는 걸 권장합니다.

여기서 BaseEntity를 이렇게 public abstract class로 해서 추상 클래스로 만들어 두시는 걸 추천을 드립니다.


BaseEntity로 뭐 할 수 있는 게 없어요. 그러니까 설계상 이런 것들을 다 추상 클래스로 만드는 게 낫죠. 누가 실수할 수도 있으니깐.

그리고 테이블과 관계가 없고 단순히 엔티티가 공통으로 사용하는 맵핑 정보를 모으는 역할입니다. 방금 예제를 본 대로, 등록일 수정일, 등록자 수정자 같은 전체 엔티티에서 공통으로 적용하는 정보를 모을 때 사용합니다. 참고로 @Entity 클래스엔티티@MappedSuperclass로 지정한 클래스만 상속할 수 있습니다.

그러니까 JPA에서 extends 라고 쓸 때는

@MappedSuperclass가 있거나, @Entity 라는 게 있거나. @Entity는 상속관계 매핑일 때 쓰는 거고, @MappedSuperclass는 속성만 상속할 때 쓰는 거고.


이렇게 두 가지로 구분해서 쓰시면 됩니다. @MappedSuperclass는 실무에서 BaseEntity 같은 거를 만들어 두시면 되게 편하게 쓸 수가 있어요. 저도 되게 많이 애용하고요. 추상 클래스로 잘 만들어 가지고 프로젝트에 맞게 잘 쓰시기를 권장 드리겠습니다.

자 여기까지 하고 실전 예제를 조금 이따 알아보겠습니다.

'스프링 > 자바 ORM 표준 JPA 프로그래밍 - 기본편' 카테고리의 다른 글

실전 예제 4 - 상속관계 매핑  (0) 2024.08.22
실전 예제 3 - 다양한 연관관계 매핑  (0) 2024.07.17
다대다 [N:M]  (0) 2024.07.14
일대일 [1:1]  (0) 2024.07.07
일대다 [1:N]  (0) 2024.06.23