-
Notifications
You must be signed in to change notification settings - Fork 6
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] Feat/#586 핀 수정 시 변경 이력 저장 이벤트 구현 #591
Changes from all commits
0bd7c7c
e6a4f40
65ef31b
0dd8fc7
19bcc6f
ae2bc06
57073b9
2a7f4db
a9b5308
9ded478
ca92508
8ed8da4
0309e78
8444f53
02519c7
20cb321
b257b24
5c1bbdb
2fc368c
3592ff0
5bfbcfc
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 |
---|---|---|
|
@@ -2,15 +2,21 @@ | |
|
||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Modifying; | ||
import org.springframework.data.jpa.repository.Query; | ||
|
||
public interface BookmarkRepository extends JpaRepository<Bookmark, Long> { | ||
|
||
Optional<Bookmark> findByMemberIdAndTopicId(Long memberId, Long topicId); | ||
|
||
boolean existsByMemberIdAndTopicId(Long memberId, Long topicId); | ||
|
||
@Modifying(clearAutomatically = true) | ||
@Query("delete from Bookmark b where b.member.id = :memberId") | ||
Comment on lines
+14
to
+15
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. flush 를 왜 다 지우셨나 했는데 @query 어노테이션도 추가적으로 붙여주시면서 @Modifying 어노테이션이 동작하게 해주셨군요! 굳굳 |
||
void deleteAllByMemberId(Long memberId); | ||
|
||
@Modifying(clearAutomatically = true) | ||
@Query("delete from Bookmark b where b.topic.id = :topicId") | ||
void deleteAllByTopicId(Long topicId); | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.mapbefine.mapbefine.history.application; | ||
|
||
import com.mapbefine.mapbefine.history.domain.PinHistory; | ||
import com.mapbefine.mapbefine.history.domain.PinHistoryRepository; | ||
import com.mapbefine.mapbefine.pin.domain.Pin; | ||
import com.mapbefine.mapbefine.pin.event.PinUpdateEvent; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.context.event.EventListener; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Transactional | ||
@Service | ||
public class PinHistoryCommandService { | ||
|
||
private final PinHistoryRepository pinHistoryRepository; | ||
|
||
public PinHistoryCommandService(PinHistoryRepository pinHistoryRepository) { | ||
this.pinHistoryRepository = pinHistoryRepository; | ||
} | ||
|
||
@EventListener | ||
public void saveHistory(PinUpdateEvent event) { | ||
Pin pin = event.pin(); | ||
pinHistoryRepository.save(new PinHistory(pin, event.member())); | ||
|
||
log.debug("pin history saved for update pin id =: {}", pin.getId()); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.mapbefine.mapbefine.history.domain; | ||
|
||
import static lombok.AccessLevel.PROTECTED; | ||
|
||
import com.mapbefine.mapbefine.common.entity.BaseTimeEntity; | ||
import com.mapbefine.mapbefine.member.domain.Member; | ||
import com.mapbefine.mapbefine.pin.domain.Pin; | ||
import com.mapbefine.mapbefine.pin.domain.PinInfo; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Embedded; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.EntityListeners; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import java.time.LocalDateTime; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
|
||
@EntityListeners(AuditingEntityListener.class) | ||
@Entity | ||
@NoArgsConstructor(access = PROTECTED) | ||
@Getter | ||
public class PinHistory extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "pin_id", nullable = false) | ||
private Pin pin; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "member_id", nullable = false) | ||
private Member member; | ||
|
||
@Embedded | ||
private PinInfo pinInfo; | ||
|
||
@Column(name = "pin_updated_at", nullable = false) | ||
private LocalDateTime pinUpdatedAt; | ||
Comment on lines
+44
to
+45
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. BaseEntity의 createdAt은 해당 엔티티가 영속화될때 저장되는데 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. Pin을 업데이트 할 때에도, pin.updatedAt은 영속화 시점에 결정되지않나요 ? 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. createdAt, updatedAt 모두 종합해서 말씀드린거였어요!! pinRepository.save(pin);
eventPublisher.publishEvent(new PinUpdateEvent(pin, member)); // pinHistoryRepository.save(...); ++ 그리고 같은 트랜잭션으로 묶여 있다 해도, 아래 코멘트에서 말씀해주신 것처럼 서로 다른 트랜잭션으로 가져가도록 변경할 여지가 있다면 별개로 관리하는 건 어떨까요? BaseEntity는 기본적으로 저장하는, '레코드'에 대한 시간 정보라는 생각도 들고요! |
||
|
||
public PinHistory(Pin pin, Member member) { | ||
this.pin = pin; | ||
PinInfo history = pin.getPinInfo(); | ||
this.pinInfo = PinInfo.of(history.getName(), history.getDescription()); | ||
this.pinUpdatedAt = pin.getUpdatedAt(); | ||
this.member = member; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.mapbefine.mapbefine.history.domain; | ||
|
||
import java.util.List; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface PinHistoryRepository extends JpaRepository<PinHistory, Long> { | ||
List<PinHistory> findAllByPinId(Long pinId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
import com.mapbefine.mapbefine.pin.dto.request.PinCreateRequest; | ||
import com.mapbefine.mapbefine.pin.dto.request.PinImageCreateRequest; | ||
import com.mapbefine.mapbefine.pin.dto.request.PinUpdateRequest; | ||
import com.mapbefine.mapbefine.pin.event.PinUpdateEvent; | ||
import com.mapbefine.mapbefine.pin.exception.PinException.PinBadRequestException; | ||
import com.mapbefine.mapbefine.pin.exception.PinException.PinForbiddenException; | ||
import com.mapbefine.mapbefine.topic.domain.Topic; | ||
|
@@ -30,16 +31,20 @@ | |
import java.util.List; | ||
import java.util.NoSuchElementException; | ||
import java.util.Objects; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
@Slf4j | ||
@Transactional | ||
@Service | ||
public class PinCommandService { | ||
|
||
private static final double DUPLICATE_LOCATION_DISTANCE_METERS = 10.0; | ||
|
||
private final ApplicationEventPublisher eventPublisher; | ||
private final PinRepository pinRepository; | ||
private final LocationRepository locationRepository; | ||
private final TopicRepository topicRepository; | ||
|
@@ -48,13 +53,15 @@ public class PinCommandService { | |
private final ImageService imageService; | ||
|
||
public PinCommandService( | ||
ApplicationEventPublisher eventPublisher, | ||
PinRepository pinRepository, | ||
LocationRepository locationRepository, | ||
TopicRepository topicRepository, | ||
MemberRepository memberRepository, | ||
PinImageRepository pinImageRepository, | ||
ImageService imageService | ||
) { | ||
this.eventPublisher = eventPublisher; | ||
this.pinRepository = pinRepository; | ||
this.locationRepository = locationRepository; | ||
this.topicRepository = topicRepository; | ||
|
@@ -81,8 +88,8 @@ public long save( | |
); | ||
|
||
addPinImagesToPin(images, pin); | ||
|
||
pinRepository.save(pin); | ||
eventPublisher.publishEvent(new PinUpdateEvent(pin, member)); | ||
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 pin.getId(); | ||
} | ||
|
@@ -139,10 +146,12 @@ public void update( | |
Long pinId, | ||
PinUpdateRequest request | ||
) { | ||
Member member = findMember(authMember.getMemberId()); | ||
Pin pin = findPin(pinId); | ||
validatePinCreateOrUpdate(authMember, pin.getTopic()); | ||
|
||
pin.updatePinInfo(request.name(), request.description()); | ||
eventPublisher.publishEvent(new PinUpdateEvent(pin, member)); | ||
} | ||
|
||
private Pin findPin(Long pinId) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.mapbefine.mapbefine.pin.event; | ||
|
||
import com.mapbefine.mapbefine.member.domain.Member; | ||
import com.mapbefine.mapbefine.pin.domain.Pin; | ||
|
||
public record PinUpdateEvent(Pin pin, Member member) { | ||
} |
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.
도이가 쓴 글에 의하면
hardDelete
가 진행되기 이전에flush
가 발생하면 되고, 그렇다면permissionRepository.deleteAllByMemberId()
를 호출하게 되면서flush
가 발생하게 되니까명시적인 flush 가 없어도 되지 않을까요??근데, 해당
flush
를 호출하지 않으면 예상한 것과 같이 동작하지 않는다고 하셨으니 추후에 같이 탐구해봐야겠군요!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.
맞아요. Repository에서 제공하는 flush를 통해 member의 update 쿼리도 같이 나갈 줄 알았는데,
그렇지 않아서 추가해주게 되었어요 ㅜㅜ
@Modifying
으로 실행되는 flush는 해당 repository 메서드의 쿼리만 flush해주는 걸까요?원인은 더 탐구해보는 것으로..