From f2923d15fec14be4fd4e04d1a3a0ce29b784a26b Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Mon, 25 Mar 2024 00:21:28 +0900 Subject: [PATCH 1/5] =?UTF-8?q?#42=20feat:=20Entity=20soft=20delete=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `@SQLDelete`로 soft delete 구현 -` @SQLDelete`로 실행된 SQL은 JPA가 제공하는 더티 체킹 메커니즘을 우회하여 직접 데이터베이스에 적용 - 따라서 영속성 컨텍스트에 변경이 감지되지 않아 modifiedAt과 같은 필드가 자동 업데이트 되지 않아 수동으로 변경 --- .../example/pnuunivmiryangcampus/reservation/Reservation.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/reservation/Reservation.java b/src/main/java/com/example/pnuunivmiryangcampus/reservation/Reservation.java index d4947aa..7a5bc80 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/reservation/Reservation.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/reservation/Reservation.java @@ -6,9 +6,12 @@ import java.time.LocalDateTime; import lombok.Getter; import lombok.ToString; +import org.hibernate.annotations.SQLDelete; + @Getter @ToString(callSuper = true) +@SQLDelete(sql = "update reservation set is_deleted = true, modified_at = current_time, modified_by = user_account_id where id = ?") @Entity public class Reservation extends AuditingFields { From 1bf821c6ce0011fdca464120fc7ad126b17bc481 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Mon, 25 Mar 2024 00:22:44 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20ReservationResponse=20seatNumber=20?= =?UTF-8?q?->=20seatId=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/dto/response/ReservationResponse.java | 10 +++++----- .../reservation/service/ReservationService.java | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/reservation/dto/response/ReservationResponse.java b/src/main/java/com/example/pnuunivmiryangcampus/reservation/dto/response/ReservationResponse.java index ea91a36..9113d37 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/reservation/dto/response/ReservationResponse.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/reservation/dto/response/ReservationResponse.java @@ -7,20 +7,20 @@ public record ReservationResponse( Long ReservationId, - Long seatNumber, + Long seatId, LocalDateTime startAt, LocalDateTime endAt, int renewalCount ) implements Serializable { - public static ReservationResponse of(Long ReservationId, Long seatNumber, LocalDateTime startAt, LocalDateTime endAt, int renewalCount) { - return new ReservationResponse(ReservationId, seatNumber, startAt, endAt, renewalCount); + public static ReservationResponse of(Long ReservationId, Long seatId, LocalDateTime startAt, LocalDateTime endAt, int renewalCount) { + return new ReservationResponse(ReservationId, seatId, startAt, endAt, renewalCount); } - public static ReservationResponse from(Reservation entity, Long seatNumber) { + public static ReservationResponse from(Reservation entity, Long seatId) { return new ReservationResponse( entity.getId(), - seatNumber, + seatId, entity.getStartAt(), entity.getEndAt(), entity.getRenewalCount() diff --git a/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java b/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java index 4f82f7a..03f8dc0 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java @@ -31,9 +31,9 @@ public ReservationResponse getReservationByUserId(Long userId) { Optional reservation = reservationRepository.findByUserAccountId(userId); if (reservation.isPresent()) { - Long reservedSeatNumber = librarySeatRepository.findById(reservation.get().getLibrarySeatId()).orElseThrow().getId(); + Long reservedSeatId = librarySeatRepository.findById(reservation.get().getLibrarySeatId()).orElseThrow().getId(); - return ReservationResponse.from(reservation.get(), reservedSeatNumber); + return ReservationResponse.from(reservation.get(), reservedSeatId); } return null; @@ -55,3 +55,4 @@ private void checkRenewalCount(Reservation reservation) { } } } + From ae1f80ca35e016ab1d5912b327e00c4ce62a99ed Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Mon, 25 Mar 2024 00:24:01 +0900 Subject: [PATCH 3/5] =?UTF-8?q?#42=20feat:=20deleteReservation=20method=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `@SQLDelete`로 인해 `deleteById` method 실행 시 사용자 정의된 쿼리문이 실행 --- .../reservation/service/ReservationService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java b/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java index 03f8dc0..37d9ef6 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/reservation/service/ReservationService.java @@ -54,5 +54,10 @@ private void checkRenewalCount(Reservation reservation) { throw new ReservationLimitExceededException(); } } + + @Transactional + public void deleteReservation(Long reservationId) { + reservationRepository.deleteById(reservationId); + } } From f023133ab463bfa513e729ffff6a46edd549a1c7 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Mon, 25 Mar 2024 00:24:36 +0900 Subject: [PATCH 4/5] =?UTF-8?q?#42=20feat:=20DELETE=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=EC=9D=98=20resevation=20method=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/controller/ReservationController.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/reservation/controller/ReservationController.java b/src/main/java/com/example/pnuunivmiryangcampus/reservation/controller/ReservationController.java index ae92fb7..c7aedf8 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/reservation/controller/ReservationController.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/reservation/controller/ReservationController.java @@ -32,7 +32,7 @@ public ResponseEntity reservation(@PathVariable Long seatId, @Authenticati ReservationDto reservationDto = ReservationDto.of(findUser.getId(), seatId, startAt, endAt); reservationService.saveReservation(reservationDto); - return ResponseEntity.created(URI.create("/library/reservation/" + findUser.getId())).build(); + return ResponseEntity.created(URI.create("/library/reservation/")).build(); } @GetMapping @@ -51,4 +51,11 @@ public ResponseEntity getReservation(@AuthenticationPrincip public ResponseEntity reservationRenewal(@PathVariable Long reservationId) { return ResponseEntity.ok(reservationService.updateReservationRenewalCount(reservationId)); } + + @DeleteMapping("/{reservationId}") + public ResponseEntity reservation(@PathVariable Long reservationId) { + reservationService.deleteReservation(reservationId); + + return ResponseEntity.noContent().build(); + } } From 588a29a7cc9d397f60491b84e756ca9ec1bff4d5 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Mon, 25 Mar 2024 00:30:44 +0900 Subject: [PATCH 5/5] =?UTF-8?q?#42=20refactor:=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=8B=9C=20soft=20delete=20=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EC=9D=80=20=EC=BB=AC=EB=9F=BC=20=EA=B0=92=EB=A7=8C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `@Where`이 존재하지만 삭제된 데이터도 조회할 수 있어야 하기 때문에 soft delete 방식을 사용하더라도 불편해도 JPQL로 삭제 데이터를 조회 - 삭제된 데이터를 사용하지 않는다면 `@Where` 사용 가능, 비즈니스 상황을 고려 - https://www.inflearn.com/questions/304378 --- .../repository/LibrarySeatRepository.java | 12 +++++++----- .../librarySeat/service/LibrarySeatService.java | 1 + .../repository/ReservationRepository.java | 6 ++++++ .../repository/UserAccountRepository.java | 2 ++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/repository/LibrarySeatRepository.java b/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/repository/LibrarySeatRepository.java index faf44bf..97a8dd5 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/repository/LibrarySeatRepository.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/repository/LibrarySeatRepository.java @@ -1,15 +1,17 @@ package com.example.pnuunivmiryangcampus.librarySeat.repository; import com.example.pnuunivmiryangcampus.librarySeat.LibrarySeat; -import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import java.util.List; +import java.util.Optional; + public interface LibrarySeatRepository extends JpaRepository { - // Optional Type 고려 - @Query("select ls from LibrarySeat ls where ls.availability = '사용가능'") - List findLibrarySeatsByAvailability(); + @Query("select ls from LibrarySeat ls where ls.isDeleted = false and ls.availability = '사용가능'") + Optional> findLibrarySeatsByAvailability(); - LibrarySeat findBySeatNumber(int seatNumber); + @Query("select ls from LibrarySeat ls where ls.isDeleted = false and ls.id = :id") + Optional findById(Long id); } \ No newline at end of file diff --git a/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/service/LibrarySeatService.java b/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/service/LibrarySeatService.java index a6f4920..0088171 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/service/LibrarySeatService.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/librarySeat/service/LibrarySeatService.java @@ -17,6 +17,7 @@ public class LibrarySeatService { @Transactional(readOnly = true) public List getAvailableLibrarySeat() { return librarySeatRepository.findLibrarySeatsByAvailability() + .orElseThrow() .stream() .map(LibrarySeatDto::from) .toList(); diff --git a/src/main/java/com/example/pnuunivmiryangcampus/reservation/repository/ReservationRepository.java b/src/main/java/com/example/pnuunivmiryangcampus/reservation/repository/ReservationRepository.java index 4f68f4e..59574c8 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/reservation/repository/ReservationRepository.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/reservation/repository/ReservationRepository.java @@ -2,9 +2,15 @@ import com.example.pnuunivmiryangcampus.reservation.Reservation; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; public interface ReservationRepository extends JpaRepository { + + @Query("select r from Reservation r where r.isDeleted = false and r.userAccountId = :userId") Optional findByUserAccountId(Long userId); + + @Query("select r from Reservation r where r.isDeleted = false and r.id = :id") + Optional findById(Long id); } \ No newline at end of file diff --git a/src/main/java/com/example/pnuunivmiryangcampus/userAccount/repository/UserAccountRepository.java b/src/main/java/com/example/pnuunivmiryangcampus/userAccount/repository/UserAccountRepository.java index 231b863..d5ae994 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/userAccount/repository/UserAccountRepository.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/userAccount/repository/UserAccountRepository.java @@ -3,8 +3,10 @@ import com.example.pnuunivmiryangcampus.userAccount.UserAccount; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; public interface UserAccountRepository extends JpaRepository { + @Query("select ua from UserAccount ua where ua.isDeleted = false and ua.sub = :sub") Optional findBySub(String sub); } \ No newline at end of file