-
Notifications
You must be signed in to change notification settings - Fork 1
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
refactor: 스타카토 양방향 연관관계 끊기 #547 #569
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,42 @@ | ||
package com.staccato.moment.domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import jakarta.persistence.CascadeType; | ||
import jakarta.persistence.Embeddable; | ||
import jakarta.persistence.OneToMany; | ||
import com.staccato.exception.StaccatoException; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Embeddable | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class MomentImages { | ||
|
||
public record MomentImages(List<MomentImage> images) { | ||
private static final int MAX_COUNT = 5; | ||
@OneToMany(mappedBy = "moment", cascade = CascadeType.ALL, orphanRemoval = true) | ||
private List<MomentImage> images = new ArrayList<>(); | ||
|
||
public MomentImages(List<String> addedImages) { | ||
validateNumberOfImages(addedImages); | ||
this.images.addAll(addedImages.stream() | ||
.map(MomentImage::new) | ||
.toList()); | ||
|
||
public MomentImages { | ||
validateNumberOfImages(images); | ||
} | ||
|
||
public static MomentImages of(List<String> imageUrls, Moment moment) { | ||
List<MomentImage> images = imageUrls.stream() | ||
.map(imageUrl -> new MomentImage(imageUrl, moment)) | ||
.toList(); | ||
return new MomentImages(images); | ||
} | ||
|
||
private void validateNumberOfImages(List<String> addedImages) { | ||
private <T> void validateNumberOfImages(List<T> addedImages) { | ||
if (addedImages.size() > MAX_COUNT) { | ||
throw new StaccatoException("사진은 5장을 초과할 수 없습니다."); | ||
} | ||
} | ||
|
||
protected void addAll(MomentImages newMomentImages, Moment moment) { | ||
newMomentImages.images.forEach(image -> { | ||
this.images.add(image); | ||
image.belongTo(moment); | ||
}); | ||
} | ||
|
||
protected void update(MomentImages momentImages, Moment moment) { | ||
removeExistsImages(new ArrayList<>(images)); | ||
addAll(momentImages, moment); | ||
public List<MomentImage> findValuesNotPresentIn(MomentImages targetMomentImages) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 특별한 이유가 없습니다! |
||
return this.images.stream() | ||
.filter(image -> !targetMomentImages.contains(image)) | ||
.toList(); | ||
} | ||
|
||
private void removeExistsImages(List<MomentImage> originalImages) { | ||
originalImages.forEach(this.images::remove); | ||
private boolean contains(MomentImage momentImage) { | ||
return this.images.stream() | ||
.anyMatch(image -> image.getImageUrl().equals(momentImage.getImageUrl())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. image에 같은지 물어보는 메서드를 분리하면 어떨까요? |
||
} | ||
|
||
public boolean isNotEmpty() { | ||
return !images.isEmpty(); | ||
public List<String> getUrls() { | ||
return images.stream() | ||
.map(MomentImage::getImageUrl) | ||
.toList(); | ||
} | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스에 메서드가 굉장히 많아졌네요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확실히 기존에
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,8 @@ | |
import com.staccato.memory.repository.MemoryRepository; | ||
import com.staccato.moment.domain.Feeling; | ||
import com.staccato.moment.domain.Moment; | ||
import com.staccato.moment.domain.MomentImage; | ||
import com.staccato.moment.domain.MomentImages; | ||
import com.staccato.moment.repository.MomentImageRepository; | ||
import com.staccato.moment.repository.MomentRepository; | ||
import com.staccato.moment.service.dto.request.FeelingRequest; | ||
|
@@ -37,8 +39,10 @@ public MomentIdResponse createMoment(MomentRequest momentRequest, Member member) | |
Memory memory = getMemoryById(momentRequest.memoryId()); | ||
validateMemoryOwner(memory, member); | ||
Moment moment = momentRequest.toMoment(memory); | ||
MomentImages newMomentImages = momentRequest.toMomentImages(moment); | ||
|
||
momentRepository.save(moment); | ||
momentImageRepository.saveAll(newMomentImages.images()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 삭제 관련된 전이를 끊으니( 양방향 연관관계를 끊으면서 Insert가 생성되는 엔티티마다 나가는 것을 하나의 BulkInsert를 통해 성능적 이점을 도모하려고 시도하였습니다. 하지만 PR에 적어놓은 것 처럼 성능적 이점은 미미했고, 더 나아가 양방향 연관관계를 끊는 것으로 인해 수정된 곳이 많아졌고, 서비스 로직에 굳이 없어도 될 비즈니스 로직이
// MomentService.java 의 updateMomentById 메서드
MomentImages momentImages = getMomentImagesBy(moment);
MomentImages newMomentImages = momentRequest.toMomentImages(moment);
removeExistImages(momentImages, newMomentImages);
saveNewImages(momentImages, newMomentImages);
이와 같은 이유로 양방향 연관관계로 다시 유지하는게 나을 것 같다는 생각이 들었습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 너무 공감합니다!! 직접 코드로 구현해보고 장단점을 비교해봤을 때 더 잘 와닿는다고 생각해요! 호티한테도 의미있는 과정이었다니 다행입니다👍👍 |
||
|
||
return new MomentIdResponse(moment.getId()); | ||
} | ||
|
@@ -57,7 +61,8 @@ public MomentLocationResponses readAllMoment(Member member) { | |
public MomentDetailResponse readMomentById(long momentId, Member member) { | ||
Moment moment = getMomentById(momentId); | ||
validateMemoryOwner(moment.getMemory(), member); | ||
return new MomentDetailResponse(moment); | ||
MomentImages momentImages = getMomentImagesBy(moment); | ||
return new MomentDetailResponse(moment, momentImages); | ||
} | ||
|
||
@Transactional | ||
|
@@ -69,18 +74,43 @@ public void updateMomentById( | |
Moment moment = getMomentById(momentId); | ||
validateMemoryOwner(moment.getMemory(), member); | ||
|
||
Memory targetMemory = getMemoryById(momentRequest.memoryId()); | ||
validateMemoryOwner(targetMemory, member); | ||
Memory memory = getMemoryById(momentRequest.memoryId()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 메서드 순서 확인해주세요! ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은 이해가 잘 가지않았습니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 컨벤션을 의미한 거였습니다! |
||
validateMemoryOwner(memory, member); | ||
|
||
Moment newMoment = momentRequest.toMoment(memory); | ||
moment.update(newMoment); | ||
|
||
Moment updatedMoment = momentRequest.toMoment(targetMemory); | ||
moment.update(updatedMoment); | ||
MomentImages momentImages = getMomentImagesBy(moment); | ||
MomentImages newMomentImages = momentRequest.toMomentImages(moment); | ||
removeExistImages(momentImages, newMomentImages); | ||
saveNewImages(momentImages, newMomentImages); | ||
} | ||
|
||
private Moment getMomentById(long momentId) { | ||
return momentRepository.findById(momentId) | ||
.orElseThrow(() -> new StaccatoException("요청하신 스타카토를 찾을 수 없어요.")); | ||
} | ||
|
||
private MomentImages getMomentImagesBy(Moment moment) { | ||
List<MomentImage> momentImages = momentImageRepository.findAllByMomentId(moment.getId()) | ||
.stream() | ||
.toList(); | ||
return new MomentImages(momentImages); | ||
} | ||
|
||
private void removeExistImages(MomentImages momentImages, MomentImages newMomentImages) { | ||
List<MomentImage> removeList = momentImages.findValuesNotPresentIn(newMomentImages); | ||
List<Long> ids = removeList.stream() | ||
.map(MomentImage::getId) | ||
.toList(); | ||
momentImageRepository.deleteAllByIdInBatch(ids); | ||
} | ||
|
||
private void saveNewImages(MomentImages momentImages, MomentImages newMomentImages) { | ||
List<MomentImage> saveList = newMomentImages.findValuesNotPresentIn(momentImages); | ||
momentImageRepository.saveAll(saveList); | ||
} | ||
|
||
@Transactional | ||
public void deleteMomentById(long momentId, Member member) { | ||
momentRepository.findById(momentId).ifPresent(moment -> { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
제네릭으로 한 이유가 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
List<String>
,List<MomentImage>
형식 모두를 호환하고자 제네릭으로 표현했었는데, 사용되는 곳은 압축생성자 한 곳이네요! 필요없어요!