Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] refactor: Club 매핑 테이블 엔티티 연관 관계 개선 #165

Merged
merged 2 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@

import com.woowacourse.friendogly.exception.FriendoglyException;
import com.woowacourse.friendogly.member.domain.Member;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -35,9 +31,6 @@ public class ClubMember {
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@OneToMany(mappedBy = "clubMember", orphanRemoval = true, cascade = CascadeType.ALL)
private List<ClubMemberPet> clubMemberPets = new ArrayList<>();

@Builder
public ClubMember(Club club, Member member) {
validateClub(club);
Expand All @@ -57,17 +50,4 @@ private void validateMember(Member member) {
throw new FriendoglyException("모임에 참여하는 회원 정보는 필수입니다.");
}
}

public void addClubMemberPets(ClubMemberPet pet) {
//TODO : 데려갈 수 있는 최대 반려견이 정해지면 예외처리
//TODO : 해당 팻이 member가 키우는 팻인지 검증
clubMemberPets.add(pet);
}

public String findOverviewPetImage() {
if (clubMemberPets.isEmpty()) {
return null;
}
return clubMemberPets.get(0).getPet().getImageUrl().getValue();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,30 @@
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class ClubMemberPet {
public class ClubPet {

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

@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "club_member_id", nullable = false)
private ClubMember clubMember;
@JoinColumn(name = "club_id", nullable = false)
private Club club;

Comment on lines 26 to 29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ManyToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "pet_id", nullable = false)
private Pet pet;

@Builder
public ClubMemberPet(ClubMember clubMember, Pet pet) {
validateClubMember(clubMember);
public ClubPet(Club club, Pet pet) {
validateClub(club);
validatePet(pet);
this.clubMember = clubMember;
this.club = club;
this.pet = pet;
}

private void validateClubMember(ClubMember clubMember) {
if (clubMember == null) {
private void validateClub(Club club) {
if (club == null) {
throw new FriendoglyException("모임에 참여하는 회원 정보는 필수입니다.");
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.woowacourse.friendogly.club.repository;

import com.woowacourse.friendogly.club.domain.ClubPet;
import java.util.List;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ClubPetRepository extends JpaRepository<ClubPet, Long> {

@EntityGraph(attributePaths = {"club", "pet"})
List<ClubPet> findAllByClubId(Long id);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.woowacourse.friendogly.club.service;

import static java.util.stream.Collectors.toList;

import com.woowacourse.friendogly.club.domain.Club;
import com.woowacourse.friendogly.club.domain.ClubMember;
import com.woowacourse.friendogly.club.domain.ClubPet;
import com.woowacourse.friendogly.club.dto.request.FindSearchingClubRequest;
import com.woowacourse.friendogly.club.dto.response.FindSearchingClubResponse;
import com.woowacourse.friendogly.club.repository.ClubMemberPetRepository;
import com.woowacourse.friendogly.club.repository.ClubMemberRepository;
import com.woowacourse.friendogly.club.repository.ClubPetRepository;
import com.woowacourse.friendogly.club.repository.ClubRepository;
import com.woowacourse.friendogly.club.repository.ClubSpecification;
import com.woowacourse.friendogly.pet.domain.Pet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand All @@ -19,16 +24,16 @@ public class ClubQueryService {

private final ClubRepository clubRepository;
private final ClubMemberRepository clubMemberRepository;
private final ClubMemberPetRepository clubMemberPetRepository;
private final ClubPetRepository clubPetRepository;

public ClubQueryService(
ClubRepository clubRepository,
ClubMemberRepository clubMemberRepository,
ClubMemberPetRepository clubMemberPetRepository
ClubPetRepository clubPetRepository
) {
this.clubRepository = clubRepository;
this.clubMemberRepository = clubMemberRepository;
this.clubMemberPetRepository = clubMemberPetRepository;
this.clubPetRepository = clubPetRepository;
}

public List<FindSearchingClubResponse> findSearching(FindSearchingClubRequest request) {
Expand All @@ -39,18 +44,23 @@ public List<FindSearchingClubResponse> findSearching(FindSearchingClubRequest re
.build();

return clubRepository.findAll(spec).stream()
.map(club -> {
List<String> overviewPetImages = clubMemberRepository.findAllByClubId(club.getId()).stream()
.map(ClubMember::findOverviewPetImage)
.toList();
return new FindSearchingClubResponse(
club,
clubMemberRepository.countByClubId(club.getId()),
overviewPetImages
);
})
.map(club -> new FindSearchingClubResponse(
club,
clubMemberRepository.countByClubId(club.getId()),
collectOverviewPetImages(club)
))
.toList();
}

private List<String> collectOverviewPetImages(Club club) {
Map<Long, List<Pet>> groupPetsByMemberId = clubPetRepository.findAllByClubId(club.getId()).stream()
.map(ClubPet::getPet)
.collect(Collectors.groupingBy(pet -> pet.getMember().getId()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굳굳 이렇게 해결됐구나..!


return groupPetsByMemberId.values().stream()
.map(petList -> petList.get(0).getImageUrl().getValue())
.collect(toList());
}
Comment on lines +55 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private List<String> collectOverviewPetImages(Club club) {
Map<Long, List<Pet>> groupPetsByMemberId = clubPetRepository.findAllByClubId(club.getId()).stream()
.map(ClubPet::getPet)
.collect(Collectors.groupingBy(pet -> pet.getMember().getId()));
return groupPetsByMemberId.values().stream()
.map(petList -> petList.get(0).getImageUrl().getValue())
.collect(toList());
}
private List<String> findPetImageUrls(Club club) {
Map<Long, List<Pet>> groupPetsByMemberId = clubPetRepository.findAllByClubId(club.getId()).stream()
.map(ClubPet::getPet)
.collect(groupingBy(pet -> pet.getMember().getId()));
return groupPetsByMemberId.values().stream()
.map(petList -> petList.get(0).getImageUrl().getValue())
.toList();
}
  1. 메서드 이름이 더 직관적이면 좋겠어요. overview는 전체 펫의 요약이라는 느낌이 들어서요.
  2. 불변 리스트로 리턴하면 더 좋겠네요!

}


Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.woowacourse.friendogly.club.domain;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

Expand Down Expand Up @@ -74,31 +73,4 @@ void create_FailNullMember() {
.isInstanceOf(FriendoglyException.class)
.hasMessage("모임에 참여하는 회원 정보는 필수입니다.");
}

@DisplayName("리스트업에 나오는 참여 강아지 사진을 반환한다.")
@Test
void findClubOverviewPetImage() {
ClubMember clubMember = ClubMember.builder()
.club(club)
.member(member)
.build();

clubMember.addClubMemberPets(ClubMemberPet.builder()
.clubMember(clubMember)
.pet(pet)
.build());

assertThat(clubMember.findOverviewPetImage()).isEqualTo(pet.getImageUrl().getValue());
}

@DisplayName("참여 중인 회원이 어떤 강아지도 데리고 가지 않는다면 null을 반환한다.")
@Test
void findClubOverviewPetImage_FailNonPets() {
ClubMember clubMember = ClubMember.builder()
.club(club)
.member(member)
.build();

assertThat(clubMember.findOverviewPetImage()).isNull();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ class ClubQueryServiceTest extends ClubServiceTest {
@DisplayName("필터링된 모임을 정보를 조회한다.")
@Test
void findSearching() {
//서울특별시 송파구 신청동, (암컷, 중성화 암컷), 크기는 소형견이 조건인 club
Club club = saveNewClub();
Club club = getSavedClub(Set.of(Gender.FEMALE, Gender.FEMALE_NEUTERED), Set.of(SizeType.SMALL));

FindSearchingClubRequest request = new FindSearchingClubRequest(
address,
Expand Down Expand Up @@ -54,4 +53,20 @@ void findSearching() {
() -> assertThat(actual.petImageUrls()).containsExactlyInAnyOrderElementsOf(expected.petImageUrls())
);
}

@DisplayName("필터링된 모임을 정보가 없으면 빈 리스트를 반환한다.")
@Test
void findSearching_Nothing() {
Club club = getSavedClub(Set.of(Gender.FEMALE, Gender.FEMALE_NEUTERED), Set.of(SizeType.SMALL));

FindSearchingClubRequest request = new FindSearchingClubRequest(
address,
Set.of(Gender.MALE),
Set.of(SizeType.SMALL)
);

List<FindSearchingClubResponse> responses = clubQueryService.findSearching(request);

assertThat(responses.isEmpty()).isTrue();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assertThat(responses.isEmpty()).isTrue();
assertThat(responses).isEmpty();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.woowacourse.friendogly.club.domain.Club;
import com.woowacourse.friendogly.club.domain.ClubMember;
import com.woowacourse.friendogly.club.domain.ClubMemberPet;
import com.woowacourse.friendogly.club.domain.ClubPet;
import com.woowacourse.friendogly.member.domain.Member;
import com.woowacourse.friendogly.pet.domain.Gender;
import com.woowacourse.friendogly.pet.domain.Pet;
Expand Down Expand Up @@ -33,31 +33,32 @@ public abstract class ClubServiceTest extends ServiceTest {
.sizeType(SizeType.SMALL)
.build();

private final Club club = Club.create(
"강아지 산책시키실 분 모아요.",
"매주 주말에 정기적으로 산책 모임하실분만",
address,
5,
member,
allowedGenders,
allowedSizes,
"https://image.com");

protected Club saveNewClub() {
protected Club getSavedClub(Set<Gender> genders, Set<SizeType> sizes) {
Copy link
Contributor

@takoyakimchi takoyakimchi Jul 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
protected Club getSavedClub(Set<Gender> genders, Set<SizeType> sizes) {
protected Club createClub(Set<Gender> genders, Set<SizeType> sizes) {

메서드명은 get으로 되어 있지만 내부적으로는 생성도 하고 있네요.
create라는 이름은 어떨까요?

memberRepository.save(member);
petRepository.save(pet);

Club club = Club.create(
"강아지 산책시키실 분 모아요.",
"매주 주말에 정기적으로 산책 모임하실분만",
address,
5,
member,
genders,
sizes,
"https://image.com");

Club savedClub = clubRepository.save(club);
ClubMember clubMember = ClubMember.builder()
.member(member)
.club(club)
.build();

Comment on lines 51 to 55
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clubMember는 member, club 순으로 생성하고
clubPet은 club, pet 순으로 생성하고 있네요.
빌더 패턴을 쓴다고 하더라도, 하나로 통일시키면 좋을 것 같아요!

ClubMemberPet clubMemberPet = ClubMemberPet.builder()
.clubMember(clubMember)
ClubPet clubPet = ClubPet.builder()
.club(club)
.pet(pet)
.build();
clubMemberRepository.save(clubMember);
clubMemberPetRepository.save(clubMemberPet);
clubPetRepository.save(clubPet);

return savedClub;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.woowacourse.friendogly.support;

import com.woowacourse.friendogly.club.repository.ClubMemberPetRepository;
import com.woowacourse.friendogly.club.repository.ClubMemberRepository;
import com.woowacourse.friendogly.club.repository.ClubPetRepository;
import com.woowacourse.friendogly.club.repository.ClubRepository;
import com.woowacourse.friendogly.footprint.repository.FootprintRepository;
import com.woowacourse.friendogly.member.repository.MemberRepository;
Expand All @@ -20,7 +20,7 @@ public abstract class ServiceTest {
protected ClubMemberRepository clubMemberRepository;

@Autowired
protected ClubMemberPetRepository clubMemberPetRepository;
protected ClubPetRepository clubPetRepository;

@Autowired
protected MemberRepository memberRepository;
Expand All @@ -34,7 +34,7 @@ public abstract class ServiceTest {
@BeforeEach
void clearDB() {
clubMemberRepository.deleteAll();
clubMemberPetRepository.deleteAll();
clubPetRepository.deleteAll();
clubRepository.deleteAll();
footprintRepository.deleteAll();
petRepository.deleteAll();
Expand Down
Loading