-
[Spring JPA] @MappedSuperClass 사용시 주의할 점Back End/Spring Data JPA 2022. 3. 4. 22:03
필자는 처음 JPA를 패스트캠퍼스에서 간단하게 배웠다.
그 중 @MappedSuperClass 가 있었는데 누가봐도 상속을 이용하여
생산성 좋은 코드를 만들 수 있는 매우매우 좋은 기능이었다.
강의의 예제에서 @MappedSuperClass 가 붙은 추상클래스에 엔티티의 ID 필드를 작성하셔서
사이드프로젝트 초기에 당연히 추상클래스 필드에 ID필드를 넣었다.
이로 인해 매우 귀찮았던 썰을 풀어본다.
* 참고로 개인적으로 JPA 스터디에 참여하면서 영한님 강의를 수강하게 되었는데,
영한님은 내가 겪은 사항을 미리 경고하시고 ID필드를 넣지 말기를 권고 하셨다. (호엥...)
한국인은 본론 먼저!
@MappedSuperClass 의 추상클래스에 @Id 필드를 절대 넣지말자.
@Id를 가진 필드를 넣게 되면 @Id에 의존적이게 되므로 코드 확장성이 매우 떨어진다.
항상 상위클래스를 만들 때, 내부에 선언할 요소들이 어디까지 영향을 미칠 수 있을지 생각하자.
다다익선은 코딩에 적용되지 않는다.
무조건 상속이 좋은 것은 아니다.
일기장
아래와 같이 BaseEntity 라는 엔티티에 상속시킬 추상클래스를 만들었다고 하자.
BaseEntity.class
@MappedSuperclass @Getter @Setter @ToString public abstract class BaseEntity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /*...*/ }
문제점이 무엇일까?
첫번째로 id의 자료형이 고정된다.
두번째로 @GeneratedValue 까지 섞여있어 id를 DB에 위임하고 싶지 않아도 방법이 없다.
필자가 이 문제를 마주한건 업무키(비지니스키)를 구성할 때 였는데, 대충 이러하다.
Item.class (복합키)
@Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name="dtype") @Getter @Entity public class Item extends BaseEntity implements Persistable<String>{ /* Table-Field Area */ @Id private String pk; @Column(name = "user_id") private Long userId; // FK private Long itemId; public static String makePK(Long itemId, Long userId){ StringBuilder sb = new StringBuilder(); sb.append(String.valueOf(itemId)); sb.append(", "); sb.append(String.valueOf(userId)); return sb.toString(); } public Item( Long itemId, Long userId ){ this.pk=makePK(itemId, userId); this.itemId=itemId; this.userId=userId; } }
Item의 PK를 itemId+userId의 조합으로 unique하게 구성하고 싶었다.
사실 데이터 벌크 CRUD 연산을 구현하면서 생긴 문제를 해결하려고 인조키를 만든거긴 한데
BaseEntity 안에 @Id 필드가 있으므로, Item.class는 런타임 때 오류를 발생시킬 것이다.
(아마 @Id가 두개니 복합키 설정하라고 오류메세지가 나올듯?)
이 때 BaseEntity 를 다른사람이 만들었거나 오래전에 만들어 잊어버린 경우 오류메세지를 보고 잘못된 방향으로 길을 걸어 시간을 허비하게 될 수도 있다.
나중에 근본적인 원인을 알게 되더라도 BaseEntity 를 수정해야하며, 이미 BaseEntity를 상속받아서 사용하고 있는 다른 도메인(엔티티)에 까지 영향을 미치게 된다.
(만약에 BaseTime -> BaseCount -> ... -> BaseEntity 로 계속 상속받아 구성했을 경우, 엔티티마다 다른 레벨의 BaseEntity를 상속받아서 구현되어있을 경우 리팩토링해야 할 코드가 기하급수적으로 많아진다.)
그 당시 필자는 BaseEntity를 수정하기 위해 거의 15개가 넘어가는 클래스 파일들을 수정하고 생성했던 것으로 기억한다.
그래도 이때의 경험으로 상속의 위험성도 알게 되었고, 특히 상위클래스 내부에 생각없이 아무거나 막 넣지 말자라는 다짐도 하게 되었다.
덕분에 클래스 파일 하나를 정의할 때, 이 파일 하나가 어디까지 영향을 끼칠 수 있는지 생각해보는 좋은 습관도 생겼다.
다다익선은 코딩에 적용되지 않는다.
728x90'Back End > Spring Data JPA' 카테고리의 다른 글
[Spring Data JPA] 페이징 page=1 부터 시작하기 (0) 2022.09.25 [Spring JPA] 중간테이블 (조인테이블) 이 있을 때 연관관계 매핑 (0) 2022.08.28 save() 메서드 호출 시, select 쿼리가 하나 더 나가요 ㅠㅠ... (1) 2022.02.17 [Spring JPA] JPA, JPQL 의 조인 시 주의할 점 (Outer, Inner, Fetch) (0) 2022.01.29 [Spring JPA] How to retrieve Only SuperClass from a class hierarchy. (0) 2022.01.28