[픽플] (고민) 게시글-모집글 간 JPA상속 Entity

이지우·2021년 4월 29일
0
post-thumbnail

픽플 전체 엔티티

게시글-모집글 관계

픽플에서는 부모인 [게시글]을 가지는 자식이 [모집글]하나뿐이다.
그럼에도 불구하고 상속을 쓰고싶은 이유는,
추후 다른 성격을 가진 게시글이 늘어날 수도 있을것이라는 기대감 때문이다.
우리 프로젝트가 상용화되어 학과에서 두고두고 사용하게 된다면, 관리하게 될 후배들에게 확장성에 대한 여지를 남겨두고 싶기 때문이다.

사실 위와 같은 기대감에 대한 내 욕심인 부분인데,
Spring boot, JPA를 처음 활용해보면서 과연 계속 사용될 가능성이 있을지 없을지도 모르면서 확장성에 대해 고민하고 있다.
하지만 완성해 보이고 싶다.

lombok등을 사용하는 데에 있어 상속이 들어가는 부분이 가장 까다로운 것 같다.
우선은 계속 공부를 하면서 관계를 잡아나가야겠다.

Entity

  • 상속 전략은 조인 전략(InheritanceType.JOINED)을 선택했다.
  • 조인 전략은 부모클래스, 자식클래스 모두 테이블을 하나씩 가지게 된다.
  • 부모 클래스는 DTYPE이라는 속성을 가진다.
  • 자식 클래스는 부모클래스의 boardId라는 pk를 fk로 가지는 속성들이 생성된다.

Board.java

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
public abstract class Board extends BaseEntity {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long boardId;

    @ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.PERSIST)
    @JoinColumn(name="account_id",referencedColumnName = "accountId",nullable = false)
    private Account writerId;

    @Size(min=2,max=50)
    @Column(nullable=false)
    private String title;

    @Size(min=2, max=2000)
    @Column(nullable=false)
    private String text;

    @Column(nullable=false)
    @Enumerated(EnumType.STRING)
    private BoardType boardType;

    @Column(nullable = false, columnDefinition = "int default 0")
    private Integer hit;

    @Column(nullable = false, columnDefinition = "int default 0")
    private Integer isDeleted;

}

Board는 BaseEntity를 상속받았는데, BaseEntity는 대부분의 Entity에 공통으로 들어가는 생성일시, 수정일시 등의 속성이다.

RecruitmentBoard.java

@Entity
@Getter
@DiscriminatorValue("R")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RecruitmentBoard extends Board {

    @Column(nullable = false, columnDefinition = "int default 0")
    private Integer recNumber;

    @Column(nullable = false, columnDefinition = "int default 0")
    private Integer payment_min;

    @Column(nullable = false, columnDefinition = "int default 0")
    private Integer payment_max;

    @Column(nullable = false)
    private LocalDateTime workStartDate;

    @Column(nullable = false)
    private LocalDateTime workEndDate;

    @Column(nullable = false, columnDefinition = "datetime default now()")
    private LocalDateTime recStartDate;

    @Column(nullable = false)
    private LocalDateTime recEndDate;

    @Builder
    public RecruitmentBoard(Long boardId, Account writerId, @Size(min = 2, max = 50) String title, @Size(min = 2, max = 2000) String text, BoardType boardType, Integer hit, Integer isDeleted, Integer recNumber, Integer payment_min, Integer payment_max, LocalDateTime workStartDate, LocalDateTime workEndDate, LocalDateTime recStartDate, LocalDateTime recEndDate) {
        super(boardId, writerId, title, text, boardType, hit, isDeleted);
        this.recNumber = recNumber;
        this.payment_min = payment_min;
        this.payment_max = payment_max;
        this.workStartDate = workStartDate;
        this.workEndDate = workEndDate;
        this.recStartDate = recStartDate;
        this.recEndDate = recEndDate;
    }
}

상속 안에서 lombok의 Builder를 사용하기 위해,
부모클래스에서는 @AllArgsConstructor로 모든 필드에 대한 생성자를 가지게 하고,
자식클래스에서는 @NoArgsConstructor, 그리고 부모클래스를 상속받은 생성자에 @Builder 어노테이션을 작성했다.

Table

실행시켜보면 실제 테이블은 어떻게 생성될까?

board

recruitment_board

recruitment_board에서는 board_id를 가진다.

이번에는 [모집글_태그]

전체 엔티티 구조를 살펴보면, 모집글-태그 간에 생기는 모집글_태그라는 엔티티가 있다. 모집글이 가지는 태그가 여러개이고, 태그 또한 여러개의 모집글과 관계를 가지기 때문에, 태그와 모집글 사이에 N:M관계가 생기기 때문에 테이블 하나를 밖으로 뺐다.
처음에는 JPA를 공부하다가 '그냥 모집글 안에서 List<tag>를 가지면 안되나?' 라는 생각을 했다. 실제로 모집글 내에서 태그라는 리스트를 가지면 실행 시 테이블이 자동으로 하나 더 생기는 것을 확인했다.
하지만 JPA특성상 오류가 생길 일이 잦다, 는 의견이 있었다. (왜 오류가 생길 일이 잦은지는 공부해봐야 할 것 같다.)
고민하다 자동생성되는 테이블과 같은 내용이지만 수동으로 빼기로 했다.

갑자기 모집글_태그에 대한 이야기를 왜 꺼냈냐면,
모집글_태그에는 모집글의 PK를 외래키로 가져야 한다.
위에서 recruitment_board에서 board_id를 pk로 가졌기 때문에,
결국 모집글_태그는 게시글의PK를 외래키로 가지는 것이 맞는가 궁금하다.

Entity

RecruitmentBoardTag.java

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RecruitmentBoardTag extends BaseEntity {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long recruitmentBoardTagId;

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
   @JoinColumn(nullable = false, name = "board_id", referencedColumnName = "boardId")
   private Board boardId;

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
   @JoinColumn(nullable = false, name = "tag_id", referencedColumnName = "tagId")
   private Tag tagId;

   public RecruitmentBoardTag(Board boardId, Tag tagId) {
       this.boardId = boardId;
       this.tagId = tagId;
   }
}

하나씩 쳐나가면서 오류가 있는지 확인해야할 것 같다.
시간이 더 있으면 가능하면 세세하게 오류를 확인하고 고쳐나가고 싶은데 가능할지 모르겠다.

profile
개발 관찰일지

0개의 댓글