-
Notifications
You must be signed in to change notification settings - Fork 1
[REFACTOR] 출석 현황 리스트 조회 / 출석 요약 정보 조회시 Calendar 적용 #241
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
Conversation
…U-econovation/EEOS-BE into refactor/BM/#240/attend-list
Walkthrough해당 PR에서는 Changes
Sequence Diagram(s)sequenceDiagram
participant C as Client
participant AS as AttendService
participant CP as CalendarProvider
participant DB as Repository
C->>AS: getMyAttendSummary/getPenaltyInfos(startDate, endDate)
alt 날짜 파라미터가 null인 경우
AS->>CP: 기본 startDate와 endDate 요청
end
AS->>DB: 데이터 조회 요청
DB-->>AS: 조회 결과 반환
AS-->>C: API 응답 반환
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (1)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 0
🧹 Nitpick comments (11)
eeos/src/main/java/com/blackcompany/eeos/program/application/dto/response/CalendarPeriodApplicationQuery.java (1)
1-15: DTO 클래스의 날짜 타입 개선 제안DTO 클래스가 기능적으로는 잘 구현되어 있습니다. 하지만
java.sql.Timestamp는 JDBC와 데이터베이스 작업을 위해 설계된 클래스로, 일반적인 애플리케이션 코드의 날짜/시간 처리에는 적합하지 않을 수 있습니다.모던 자바에서는 다음과 같은 Java 8+ 날짜/시간 API를 사용하는 것이 좋습니다:
-import java.sql.Timestamp; +import java.time.LocalDateTime; @Getter @AllArgsConstructor @NoArgsConstructor public class CalendarPeriodApplicationQuery implements AbstractApplicationDto { - private Timestamp startDate; - private Timestamp endDate; + private LocalDateTime startDate; + private LocalDateTime endDate; }이렇게 변경하면 더 풍부한 날짜/시간 처리 API를 활용할 수 있고, 타입 변환 시 발생할 수 있는 문제도 줄일 수 있습니다.
eeos/src/main/java/com/blackcompany/eeos/program/application/dto/request/CalendarApplicationCommand.java (1)
1-10: 날짜 타입 및 검증 로직 개선 제안레코드를 사용한 불변 데이터 구조 설계와 검증 애노테이션 적용은 좋은 방식입니다. 두 가지 개선 사항을 제안합니다:
java.sql.Timestamp대신 Java 8+ 날짜/시간 API 사용:-import java.sql.Timestamp; +import java.time.LocalDateTime; public record CalendarApplicationCommand( - @NotNull(message = "시작 날짜는 필수입니다") Timestamp startDate, - @NotNull(message = "종료 날짜는 필수입니다") Timestamp endDate) + @NotNull(message = "시작 날짜는 필수입니다") LocalDateTime startDate, + @NotNull(message = "종료 날짜는 필수입니다") LocalDateTime endDate) implements AbstractApplicationDto {}
- 시작 날짜가 종료 날짜보다 앞서야 한다는 추가 검증 로직 도입:
// 클래스 레벨에 아래 애노테이션 추가 @CheckStartDateBeforeEndDate public record CalendarApplicationCommand(...)그리고 별도의 커스텀 검증 애노테이션을 구현하여 두 날짜의 순서를 검증하는 것이 좋습니다.
eeos/src/main/java/com/blackcompany/eeos/target/application/service/AttendService.java (1)
279-282: TODO 주석이 남아있습니다.이미
calendarProvider를 사용하여 시작일과 종료일을 설정하고 있으므로, 279번 라인의 TODO 주석은 더 이상 필요하지 않습니다.- // TODO: startDate 와 endDate 시간 설정하기 Timestamp startDate = calendarProvider.getCalendar().getStartDate(); Timestamp endDate = calendarProvider.getCalendar().getEndDate();eeos/src/main/java/com/blackcompany/eeos/program/presentation/controller/CalendarController.java (1)
24-31: TODO 코멘트 처리 및 HTTP 상태 코드 검토 필요
어드민 검증에 대한 TODO 코멘트가 있습니다. 이 작업이 후속 PR에서 처리될 예정인지, 아니면 현재 PR에서 해결해야 하는지 명확히 하는 것이 좋을 것 같습니다.
PUT 요청에 대해 HTTP 상태 코드로 CREATED(201)를 반환하고 있습니다. 일반적으로 PUT 요청(리소스 업데이트)에는 OK(200) 또는 NO_CONTENT(204)가 더 적합합니다. CREATED는 보통 POST 요청(새 리소스 생성)에 사용됩니다.
- return ApiResponseGenerator.success(response, HttpStatus.CREATED, MessageCode.CREATE); + return ApiResponseGenerator.success(response, HttpStatus.OK, MessageCode.UPDATE);eeos/src/main/java/com/blackcompany/eeos/program/application/model/CalendarModel.java (2)
19-37: 날짜 계산 로직 개선 제안기본 생성자에서 학기 기간을 계산하는 로직이 잘 구현되어 있으나, 몇 가지 개선 사항을 제안합니다:
- 복잡한 종료일 계산 로직(27-31라인)을 별도의 헬퍼 메소드로 추출하여 가독성을 높이는 것이 좋습니다.
- 종료일을 23:59:59로 설정하는 것보다 다음날 00:00:00(경계 제외)로 설정하는 패턴이 날짜 계산시 오류를 줄일 수 있습니다.
- 학기 기간(3월
8월, 9월2월)이 하드코딩되어 있어 변경 시 코드 수정이 필요합니다. 향후 유연성을 위해 설정으로 관리하는 방안을 고려해보세요.Timestamp대신 Java 8의LocalDateTime을 사용하는 것이 더 현대적인 접근법입니다.- public CalendarModel() { - LocalDate now = LocalDate.now(); - - // 9월 이후이면 9월 1일부터 다음 해 2월 말까지 - if (now.getMonthValue() >= Month.SEPTEMBER.getValue()) { - startDate = Timestamp.valueOf(LocalDate.of(now.getYear(), Month.SEPTEMBER, 1).atStartOfDay()); - endDate = - Timestamp.valueOf( - LocalDate.of( - now.getYear() + 1, - Month.FEBRUARY, - Month.FEBRUARY.length(Year.isLeap(now.getYear() + 1))) - .atTime(23, 59, 59)); - } else { - // 3월 이후이면 3월 1일부터 8월 말까지 - startDate = Timestamp.valueOf(LocalDate.of(now.getYear(), Month.MARCH, 1).atStartOfDay()); - endDate = Timestamp.valueOf(LocalDate.of(now.getYear(), Month.AUGUST, 31).atTime(23, 59, 59)); - } - } + public CalendarModel() { + LocalDate now = LocalDate.now(); + initializeDefaultPeriod(now); + } + + private void initializeDefaultPeriod(LocalDate now) { + if (now.getMonthValue() >= Month.SEPTEMBER.getValue()) { + // 9월 이후이면 9월 1일부터 다음 해 2월 말까지 + setFirstSemesterPeriod(now.getYear()); + } else { + // 3월 이후이면 3월 1일부터 8월 말까지 + setSecondSemesterPeriod(now.getYear()); + } + } + + private void setFirstSemesterPeriod(int year) { + startDate = Timestamp.valueOf(LocalDate.of(year, Month.SEPTEMBER, 1).atStartOfDay()); + // 다음날 00:00:00 사용으로 경계값 문제 방지 + LocalDate endLocalDate = LocalDate.of( + year + 1, + Month.MARCH, + 1); + endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + } + + private void setSecondSemesterPeriod(int year) { + startDate = Timestamp.valueOf(LocalDate.of(year, Month.MARCH, 1).atStartOfDay()); + // 다음날 00:00:00 사용으로 경계값 문제 방지 + LocalDate endLocalDate = LocalDate.of(year, Month.SEPTEMBER, 1); + endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + }
14-14: 미사용 로그 어노테이션
@Slf4j어노테이션이 선언되어 있지만 클래스 내에서 로깅이 사용되지 않고 있습니다. 사용하지 않는 경우 제거하거나, 날짜 계산 로직에 디버그 로그를 추가하는 것이 좋습니다.eeos/src/main/java/com/blackcompany/eeos/program/persistence/CalendarEntity.java (2)
19-23: 인덱스 이름과 컬럼 리스트 간의 불일치인덱스 이름(
idx_calendar_created_date_id)과 실제 컬럼 리스트(createdDate DESC, calendar_id DESC)가 정확히 일치하지 않습니다. 인덱스 이름에 포함된 컬럼명과 실제 컬럼명을 일치시키는 것이 유지보수성에 도움이 됩니다.@Index( name = "idx_calendar_created_date_id", - columnList = "createdDate DESC, calendar_id DESC") + columnList = "created_date DESC, calendar_id DESC")
34-38: 날짜 타입 개선 제안
startDate와endDate필드에Timestamp타입을 사용하고 있습니다. JDBC 타입인Timestamp대신 Java 8의LocalDateTime을 사용하면 더 현대적이고 타입 안전한 날짜 처리가 가능합니다. JPA 2.2 이상에서는LocalDateTime을 기본 지원합니다.- private Timestamp startDate; + private LocalDateTime startDate; - private Timestamp endDate; + private LocalDateTime endDate;또한, 관련 import문도 수정이 필요합니다:
-import java.sql.Timestamp; +import java.time.LocalDateTime;eeos/src/main/java/com/blackcompany/eeos/program/persistence/CalendarRepositoryImpl.java (3)
1-8: 필요한 import 선언이 누락된 것 같습니다.
CalendarEntity클래스를 사용하고 있지만 import 문에 선언되어 있지 않습니다. 필요한 import를 추가해주세요.package com.blackcompany.eeos.program.persistence; import com.blackcompany.eeos.program.application.model.CalendarModel; import com.blackcompany.eeos.program.application.repository.CalendarRepository; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import com.blackcompany.eeos.program.persistence.entity.CalendarEntity;
26-31: toModel 메서드의 개선 가능성현재 엔티티에서 모델로 변환할 때
startDate와endDate필드만 매핑하고 있습니다. 엔티티에 다른 중요한 필드(예: ID)가 있다면 이를 모델에도 포함시키는 것이 좋을 수 있습니다. 또한 null 체크도 고려해보세요.private CalendarModel toModel(CalendarEntity entity) { + if (entity == null) { + return null; + } return CalendarModel.builder() + .id(entity.getId()) .startDate(entity.getStartDate()) .endDate(entity.getEndDate()) .build(); }
33-38: toEntity 메서드의 개선 가능성현재 모델에서 엔티티로 변환할 때
startDate와endDate필드만 매핑하고 있습니다. 업데이트 시나리오에서는 ID를 포함시켜야 할 수 있습니다. 또한 null 체크도 고려해보세요.private CalendarEntity toEntity(CalendarModel model) { + if (model == null) { + return null; + } return CalendarEntity.builder() + .id(model.getId()) .startDate(model.getStartDate()) .endDate(model.getEndDate()) .build(); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
eeos/src/main/java/com/blackcompany/eeos/program/application/dto/request/CalendarApplicationCommand.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/dto/response/CalendarPeriodApplicationQuery.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/model/CalendarModel.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/repository/CalendarRepository.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/service/CalendarService.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/support/CalendarProvider.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/usecase/GetCalendarUsecase.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/application/usecase/UpdateCalendarUsecase.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/persistence/CalendarEntity.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/persistence/CalendarRepositoryImpl.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/persistence/JpaCalendarRepository.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/presentation/controller/CalendarController.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/program/presentation/dto/UpdateCalendarRequest.java(1 hunks)eeos/src/main/java/com/blackcompany/eeos/target/application/service/AttendService.java(4 hunks)
🔇 Additional comments (19)
eeos/src/main/java/com/blackcompany/eeos/program/application/support/CalendarProvider.java (1)
1-16: 잘 구현된 캘린더 제공자 클래스이 캘린더 제공자 클래스는 리포지토리와 서비스 계층 사이의 인터페이스 역할을 잘 수행하고 있습니다. 다음과 같은 좋은 설계 원칙들이 적용되었습니다:
- 의존성 주입을 사용하여 결합도를 낮추었습니다
- 단일 책임 원칙을 따라 캘린더 데이터 제공이라는 하나의 역할만 수행합니다
orElse를 사용하여 널 안전성을 확보했습니다다만,
getCalendar()에서 리포지토리에서 데이터를 가져오지 못했을 때 로깅을 추가하는 것을 고려해볼 수 있습니다.eeos/src/main/java/com/blackcompany/eeos/program/application/usecase/GetCalendarUsecase.java (1)
1-7: 클린 아키텍처를 잘 적용한 유스케이스 인터페이스이 인터페이스는 클린 아키텍처의 유스케이스 패턴을 잘 따르고 있습니다. 메서드가 명확하게 정의되어 있고, 단일 책임을 가지며, 인터페이스 분리 원칙(ISP)을 잘 적용하고 있습니다. 이렇게 인터페이스를 통해 계약을 정의함으로써 의존성 역전 원칙(DIP)도 만족시키고 있어 좋습니다.
eeos/src/main/java/com/blackcompany/eeos/program/application/usecase/UpdateCalendarUsecase.java (1)
6-8: 잘 정의된 인터페이스입니다.이 인터페이스는 캘린더를 업데이트하기 위한 명확한 계약을 정의합니다. 명령-쿼리 분리 원칙을 따르고 있으며, 메서드 시그니처가 간결하고 명확합니다.
eeos/src/main/java/com/blackcompany/eeos/program/presentation/dto/UpdateCalendarRequest.java (2)
7-9: 유효성 검증이 잘 구현되어 있습니다.시작일과 종료일에 대한
@NotNull검증과 한글 에러 메시지가 명확하게 제공되어 있습니다.
11-14: 날짜 로직 검증이 적절합니다.종료일이 시작일 이후인지 확인하는 유효성 검증이 잘 구현되어 있습니다. 단순히 타임스탬프 값을 비교하는 방식으로 효율적으로 구현되었습니다.
eeos/src/main/java/com/blackcompany/eeos/target/application/service/AttendService.java (3)
15-15: 새로운 의존성이 적절하게 추가되었습니다.
CalendarProvider임포트가 추가되었습니다.
90-90: 의존성 주입이 올바르게 설정되었습니다.
CalendarProvider가 필드로 추가되어 생성자 주입을 통해 적절하게 사용될 수 있습니다.
250-252: 날짜 초기화 로직이 개선되었습니다.시작일과 종료일이 제공되지 않았을 때
calendarProvider를 통해 동적으로 가져오도록 개선되었습니다. 하드코딩된 값 대신 중앙화된 날짜 관리 방식을 사용하여 유지보수성이 향상되었습니다.eeos/src/main/java/com/blackcompany/eeos/program/application/service/CalendarService.java (3)
14-20: 서비스 클래스가 잘 구성되어 있습니다.
CalendarService는 적절한 Spring 어노테이션을 사용하고 있으며, 필요한 의존성을 생성자 주입을 통해 받고 있습니다. 또한 인터페이스를 구현하여 느슨한 결합을 유지하고 있습니다.
21-25: 캘린더 조회 메서드가 잘 구현되어 있습니다.
getCalendar메서드는calendarProvider를 통해 캘린더 모델을 가져와 적절한 응답 객체로 변환하고 있습니다.
27-34: 트랜잭션 관리가 적절하게 구현되어 있습니다.
updateCalendar메서드는@Transactional어노테이션을 통해 쓰기 작업에 대한 트랜잭션을 적절하게 관리하고 있습니다. 또한 명령 객체의 값을 모델로 변환하고 저장소를 통해 업데이트한 후 응답 객체를 반환하는 로직이 명확합니다.eeos/src/main/java/com/blackcompany/eeos/program/presentation/controller/CalendarController.java (2)
1-20: 코드 구조가 깔끔하게 작성되었습니다.컨트롤러 클래스가 적절히 구성되어 있으며, 의존성 주입이 생성자를 통해 이루어지고 있어 좋은 패턴을 따르고 있습니다.
33-37: GET 엔드포인트 구현이 적절합니다.캘린더 정보를 조회하는 API가 잘 구현되어 있습니다. 적절한 HTTP 상태 코드와 메시지 코드를 사용하고 있습니다.
eeos/src/main/java/com/blackcompany/eeos/program/persistence/JpaCalendarRepository.java (1)
1-8: 적절한 JPA 레포지토리 인터페이스 정의Spring Data JPA 패턴을 잘 따르고 있으며,
findTopByOrderByCreatedDateDesc()메서드를 통해 가장 최근에 생성된 캘린더 엔티티를 조회하는 기능이 명확합니다.Optional을 반환 타입으로 사용하여 값이 없을 수 있는 상황을 적절히 처리하고 있습니다.eeos/src/main/java/com/blackcompany/eeos/program/application/repository/CalendarRepository.java (1)
1-10: 잘 설계된 레포지토리 인터페이스애플리케이션 계층에서의 레포지토리 패턴을 잘 구현하고 있습니다.
getCalendar()에서Optional을 반환 타입으로 사용하여 값이 없을 수 있는 상황을 적절히 처리하고 있으며, 메소드 이름이 기능을 명확하게 나타내고 있습니다.eeos/src/main/java/com/blackcompany/eeos/program/persistence/CalendarEntity.java (1)
11-26: 엔티티 구조 및 소프트 삭제 구현
CalendarEntity클래스의 전반적인 구조가 잘 설계되어 있습니다.@SQLDelete와@Where어노테이션을 사용한 소프트 삭제 구현이 적절하게 되어 있으며, 생성자에 대한 접근 제한자(@NoArgsConstructor(access = AccessLevel.PROTECTED),@AllArgsConstructor(access = AccessLevel.PRIVATE))도 JPA 엔티티에 적합하게 설정되어 있습니다.eeos/src/main/java/com/blackcompany/eeos/program/persistence/CalendarRepositoryImpl.java (3)
11-12: 적절한 의존성 주입 방식을 사용하고 있습니다.
@RequiredArgsConstructor와final필드를 사용하여 의존성 주입을 처리한 것은 좋은 방식입니다. Spring에서 권장하는 생성자 주입 패턴을 따르고 있습니다.
14-17: 코드가 간결하고 Optional을 적절히 활용하고 있습니다.
findTopByOrderByCreatedDateDesc()를 통해 최신 캘린더 엔티티를 조회하고, Optional의map메서드를 사용하여 엔티티를 모델로 변환하는 방식이 효율적입니다.
19-24:Details
❓ Verification inconclusive
ID 처리에 대한 고려가 필요합니다.
현재
updateCalendar메서드에서는 ID 필드를 처리하지 않고 있습니다. 이 메서드가 새로운 엔티티를 생성하는 것인지, 기존 엔티티를 업데이트하는 것인지 명확하지 않습니다. 의도에 따라 ID 필드를 처리하는 로직을 추가하는 것이 좋겠습니다.
🌐 Web query:
Spring Data JPA 에서 save 메서드의 동작 방식은?💡 Result:
Spring Data JPA의
save()메서드는 엔티티의 상태에 따라 persist 또는 merge를 선택적으로 호출합니다. 이 동작은 엔티티가 새로운 객체인지 여부를 판단하는isNew()메서드를 기반으로 결정됩니다.기본 동작 방식
새로운 엔티티 저장 (INSERT)
- ID가
null이거나@GeneratedValue로 생성된 경우:em.persist()를 호출하여 즉시 INSERT 쿼리를 생성하지 않고, 트랜잭션 커밋 시점에 실행됩니다.- 예시 코드:
@Entity public class Item { @Id @GeneratedValue private Long id; // ID가 자동 생성되는 경우 }기존 엔티티 수정 (UPDATE)
- ID가 이미 존재하는 경우:
em.merge()를 호출합니다. 이때 SELECT 쿼리를 먼저 실행하여 DB에 해당 엔티티가 존재하는지 확인한 후, 없으면 INSERT, 있으면 UPDATE 쿼리를 실행합니다[1][4][14].- 예시 코드:
Item item = itemRepository.findById(1L).orElseThrow(); item.setName("Updated"); // Dirty Checking으로 UPDATE 처리
ID를 직접 할당하는 경우의 문제점
수동으로 ID를 설정하는 엔티티에서는
isNew()가false로 판단되어merge()가 호출되며, 이로 인해 불필요한 SELECT 쿼리가 발생합니다[1][4][14].@Entity public class Item { @Id private String id; // ID를 수동으로 할당 }해결 방법:
Persistable인터페이스를 구현하여isNew()로직을 재정의합니다.@Entity @EntityListeners(AuditingEntityListener.class) public class Item implements Persistable<String> { @Id private String id; @CreatedDate // 엔티티 저장 시 자동으로 설정됨 private LocalDateTime createdDate; @Override public boolean isNew() { return createdDate == null; // 생성 시간으로 새로운 엔티티 판단 } }
@CreatedDate필드가null이면 새로운 엔티티로 간주되어persist()가 호출됩니다[1][4][12].
Merge vs. Dirty Checking
Merge 사용 시 문제점:
- 전체 컬럼을 UPDATE하며, SELECT 쿼리가 선행됩니다[2][4].
- 권장되지 않으며, Dirty Checking을 통해 변경된 필드만 UPDATE하는 것이 효율적입니다[2][3].
Dirty Checking 예시:
@Transactional public void updateItem(Long id, String newName) { Item item = itemRepository.findById(id).orElseThrow(); item.setName(newName); // 별도의 save() 호출 없이 트랜잭션 종료 시 자동 반영 }
성능 최적화 팁
save()대신 Dirty Checking 사용:
트랜잭션 내에서 엔티티를 조회하고 필드를 수정하면save()없이도 UPDATE가 자동 반영됩니다[3][6].saveAll()사용:
여러 엔티티를 저장할 때saveAll()을 사용하면 트랜잭션 1회로 처리되어 성능이 향상됩니다[9].
요약
save()는 ID 생성 전략과 엔티티 상태(new 또는 managed)에 따라 동작이 달라집니다.- ID를 수동으로 할당할 경우
Persistable구현이 필수적입니다.- 업데이트 시에는
save()보다 Dirty Checking을 활용하는 것이 성능상 유리합니다.Citations:
- 1: https://velog.io/@pjh612/JPA-Spring-Data-JPA%EC%9D%98-save%EC%9D%98-%EB%8F%99%EC%9E%91-%EA%B3%BC%EC%A0%95
- 2: https://ndm-tech.tistory.com/6
- 3: https://jaehoney.tistory.com/273
- 4: https://velog.io/@dnflrhkddyd/Spring-Data-JPA-Save-Method-%EB%8F%99%EC%9E%91-%EB%B0%A9%EC%8B%9D
- 5: https://makemepositive.tistory.com/49
- 6: https://brunch.co.kr/@springboot/595
- 7: https://insanelysimple.tistory.com/300
- 8: https://howisitgo1ng.tistory.com/entry/JPA-JPA%EA%B0%80-Entity%EB%A5%BC-%ED%8C%90%EB%B3%84%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95%EA%B3%BC-save%EC%9D%98-%EB%B9%84%EB%B0%80entityInformationisNewentity
- 9: https://yainii.tistory.com/28
- 10: https://findthelostedhobby.tistory.com/entry/TIL-Spring-Data-JPA%EC%97%90%EC%84%9C-save-%EB%A9%94%EC%84%9C%EB%93%9C%EC%9D%98-%EC%93%B0%EC%9E%84
- 11: https://itconquest.tistory.com/entry/Spring-Boot-JPA%EC%97%90%EC%84%9C-save%EA%B0%80-update-%EC%97%AD%ED%95%A0%EC%9D%84-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0
- 12: https://jbluke.tistory.com/460
- 13: https://brunch.co.kr/@anonymdevoo/47
- 14: https://programmer-chocho.tistory.com/80
- 15: https://yainii.tistory.com/29
- 16: https://velog.io/@rainmaker007/spring-data-jpa-save-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC
- 17: https://wangtak.tistory.com/2
- 18: https://choieungi.github.io/posts/Spring-data-jpa-save/
- 19: https://dncjf64.tistory.com/458
- 20: https://umanking.github.io/2019/04/12/jpa-persist-merge/
ID 필드 처리 로직 검토 필요
현재updateCalendar()메서드에서는toEntity(model)호출 결과를 즉시jpaCalendarRepository.save()로 전달하고 있습니다. Spring Data JPA의save()메서드는 엔티티의 ID 상태에 따라 신규 엔티티(persist) 또는 기존 엔티티 업데이트(merge)를 결정합니다.
- 만약
CalendarEntity의 ID가@GeneratedValue등을 통해 자동으로 관리된다면, ID 필드에 대한 별도의 처리가 없더라도 정상적으로 동작할 수 있습니다.- 하지만 업데이트가 의도된 경우라면, 전달받은
CalendarModel에 올바른 ID 값이 포함되어 있는지 확인하거나, 엔티티가 기존에 존재하는지 검증하는 로직을 추가하는 것이 좋겠습니다.- 만약 수동으로 ID가 지정되거나, 업데이트와 신규 생성의 로직이 명확히 구분되어야 한다면,
Persistable인터페이스를 구현하여isNew()메서드로 신규 여부를 재정의하는 방법도 고려해 보시기 바랍니다.해당 부분에 대해 위의 사항을 검토하시어, 의도에 맞는 ID 처리가 구현될 수 있도록 추가 검토 및 수정 부탁드립니다.
📌 관련 이슈
closes #240
✒️ 작업 내용
스크린샷 🏞️ (선택)
💬 REVIEWER에게 요구사항 💬
Summary by CodeRabbit