- 오늘 한 것
- 팀 프로젝트
팀 프로젝트
팀프로젝트 필수 요구사항들을 끝내고 추가 요구사항중 팔로우 기능을 구현하기로 했다.
기능을 구현하기전 엔티티 설계와 ERD 를 작성했다.
팔로우 엔티티 설계
팔로우는 팔로우를 받는 팔로워_id와 팔로우를하는 팔로잉_id를 갖고있다.
entity면 2개의 회원 엔티티이다.
처음에는 이를 회원과 각각 ManyToOne 관계를 맺었는데, 다음과 같은 이유로 복합키를 가진 엔티티로 변경했다.
1. 팔로우 관계가 팔로우 테이블과 회원 테이블 의 연관이 되어있는게 맞는가?
예를들어 게시판과 게시판 타입의 관계를 생각해보면 게시판의 타입을 수정할 때마다 게시판 타입이 변경될 수 있다.
게시판의 상태에 따라 게시판 타입도 변경되는 것이다. 그러므로 둘은 서로 관계를 가지고있다.
하지만, 팔로우 관계는 팔로우와 팔로잉 간의 상태로 결정되지 팔로잉 이나 팔로우를 참조하고있는 회원자체의 상태로 변경되는게
아니라는 생각이 들었다. 그래서 연관관계를 설정하지 않고 복합키 테이블로 만들기로 했다.
2. 기존에 사용하는 식별자 id 가 필요가 없음
기존에 특정 엔티티를 찾는다면 해당 entity의 id가 필요했다.
팔로우 엔티티를 find한다 했을 때, 팔로우는 식별자 id가 아닌 팔로우 회원과 팔로잉 회원의 관계로 존재하므로 해당 두 회원의
아이디가 필요하다.
그럼 jpa repository에서는 findByFollowerIdAndFollowingId 이런식으로 찾게 된다.
JPA를 이용한 복합키 매핑 방법
JPA에서 복합키 엔티티를 매핑하는 방법은 @Embeded 를 통한 매핑, @IdClass 를 통한 매핑이 존재한다.
각 방법의 장단점은 아래와 같다.
구분 | @Embeded | @IdClass |
장점 | – 객체지향적이다. (예제의 shopNumber 컬럼체크) – @MapsId를 이용한 객체생성 편리 |
– 비즈니스적으로 의미있는 PK 값이라면 명시적으로 필드를 노출할 수 있다. – 식별관계 매핑을 여러 테이블에서 사용할때, 객체 연관관계를 단순하게 유지 가능 |
단점 | – 복합키구조가 2개이상 테이블에 식별관계로 매핑이 될때 복잡도가 증가한다. | – 컬럼에 대한 필드선언이 중복이 발생한다. – @MapsId 활용이 불가능하여 객체 생성할때 주의를 요함 |
팔로우 엔티티는 팔로우 id 필드 와 팔로워 id 필드 값이 중요하므로
해당 필드들을 명시적으로 나타낼 수 있는 @IdClass를 방법으로 코드를 작성했다.
팔로우 Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@IdClass(FollowPk.class)
@Table(name = "follow")
@Entity
public class Follow {
@Id
private Long followerId; //팔로워
@Id
private Long followingId; //팔로잉
public Follow(Long followerId, Long followingId) {
this.followerId = followerId;
this.followingId = followingId;
}
public static Follow of(Long followerId, Long followingId) {
return new Follow(followerId, followingId);
}
}
팔로우 복합키 ID 클래스
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@EqualsAndHashCode
public class FollowPk implements Serializable {
private Long followerId;
private Long followingId;
public static FollowPk of(Long followerId, Long followingId) {
return new FollowPk(followerId, followingId);
}
}
@IdClass를 사용하기 위한 식별자 클래스를 생성할 때는 다음과 같은 조건이 만족해야한다.
1. 식별자 클래스의 변수명과 엔티티에서 사용되는 변수명이 동일
2. 디폴트 생성자가 존재 (위의 코드는 Lombok의 @NoArgsConstructor어노테이션 추가로 자동 생성)
3. 식별자 클래스의 접근 지정자는 public
4. Serializable을 상속
5. equals, hashCode 구현 (위의 코드는 Lombok의 @EqualsAndHashCode
복합키 Entity 사용하기
작성한 복합키 엔티티는 다음과 같이 사용한다.
Follow Repository
public interface FollowRepository extends JpaRepository<Follow, FollowPk> {
List<Follow> findAllByFollowingId(Long followerId);
}
FollowService 일부
@Transactional
public void follow(Long followerId, MemberDto following) {
//팔로잉할 회원정보가 존재하는지 확인
if (!memberRepository.existsById(followerId)) {
throw new MemberNotFoundException();
}
//자기자신을 팔로우하는건지 확인
if(followerId.equals(following.getId())) {
throw new ApiException(INVALID_VALUE);
}
//이미 팔로잉 했는지 확인
FollowPk id = FollowPk.of(followerId, following.getId());
if (followRepository.existsById(id)) {
throw new AlreadyExistFollowingException();
}
Follow follow = Follow.of(id.getFollowerId(), id.getFollowingId());
followRepository.save(follow);
}
Reference
https://techblog.woowahan.com/2595/
'TIL' 카테고리의 다른 글
2023.11.29 TIL - 단위테스트와 Mockito (0) | 2023.11.29 |
---|---|
2023.11.28 TIL - OAuth란? (0) | 2023.11.28 |
2023.11.22 TIL - 엔티티를 저장할 때, 연관관계 엔티티 저장 방법에 대해서 (feat. referenceBy) (0) | 2023.11.22 |
2023.11.21 TIL (0) | 2023.11.21 |
2023.11.17 TIL (0) | 2023.11.17 |