동기부여를 위한 챌린지 서비스에서 사용자가 챌린지를 생성하기도 하고 이미 존재하는 챌린지에 참여를 할 수도 있다. 이 때 유저와 챌린지 테이블간의 다대다 관계가 발생했다.
다대다 관계는 서로가 서로를 맵핑하기 때문에 단순하게 서로가 서로를 갖도록 구현하면 JPA에서 여러가지 에러가 발생하게 된다.
중간 테이블을 생성해서 N:M 관계를 1:N, M:1로 분리시켰다. 즉, 유저와 챌린지의 관계를 중간에 참여 테이블을 생성해서 유저와 참여, 참여와 챌린지 테이블로 나누게 된다.
챌린지 테이블에서는 챌린지의 정보만 갖게 되고 참여테이블에서는 어떤 유저가 어떤 챌린지를 참여하고 있는지를 관리하도록 했다.
Challenge
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@Where(clause="deleted_at is NULL")
public class Challenge {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String description;
private boolean vigibility;
@Enumerated(EnumType.STRING)
private AuthenticationType authenticationType;
private Long userId;
private LocalDate startDate;
private LocalDate endDate;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime modifiedAt;
private LocalDateTime deletedAt;
//...
}
User
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String email;
private String picture;
private String oauthId;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserRole role;
//...
}
Participation
@Entity
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Participation {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="user_id")
private User user;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="challenge_id")
private Challenge challenge;
//...
}