[FEAT] BaseEntity 추가 - #6
Conversation
📝 WalkthroughWalkthrough
ChangesBase Entity 및 Auditing 설정
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (4)
src/main/java/com/mr/global/entity/BaseCreatedEntity.java (1)
1-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win필드 중복, 상속으로 한 번에 정리해봐요! 👍
BaseCreatedEntity의createdAt선언이BaseTimeEntity,BaseCreatedDeletedEntity,BaseTimeDeletedEntity에서도 그대로 반복되고 있습니다(제공된 컨텍스트 스니펫 기준). Java는 다중 상속이 불가능하니,BaseCreatedEntity를 최상위로 두고BaseTimeEntity가 이를 상속해updatedAt만 추가하고,BaseCreatedDeletedEntity도 이를 상속해deletedAt만 추가하는 구조로 리팩터링하면@CreatedDate필드 선언 중복을 없앨 수 있습니다.♻️ 제안: 상속 구조로 중복 제거
-public abstract class BaseTimeEntity { +public abstract class BaseTimeEntity extends BaseCreatedEntity { - `@CreatedDate` - `@Column`(name = "created_at", nullable = false, updatable = false) - protected LocalDateTime createdAt; `@LastModifiedDate` `@Column`(name = "updated_at") protected LocalDateTime updatedAt; }지금 시점(초기 도입 단계)에 정리해두면 나중에 4개 클래스를 따로 유지보수하는 수고를 덜 수 있어요.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/mr/global/entity/BaseCreatedEntity.java` around lines 1 - 20, `BaseCreatedEntity`의 `createdAt`이 다른 공통 엔티티들에서도 중복 선언되고 있으므로, 상속 구조를 정리해 중복을 제거하세요. `BaseCreatedEntity`를 공통 최상위로 유지하고 `BaseTimeEntity`는 이를 상속해 `updatedAt`만 추가, `BaseCreatedDeletedEntity`와 `BaseTimeDeletedEntity`도 각각 필요한 필드만 덧붙이도록 구조를 맞추세요. `BaseCreatedEntity`, `BaseTimeEntity`, `BaseCreatedDeletedEntity`, `BaseTimeDeletedEntity`의 필드 선언과 상속 관계를 함께 수정해 `@CreatedDate` 중복을 없애면 됩니다.src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java (2)
21-22: 🧹 Nitpick | 🔵 Trivial
deleted_at컬럼에 인덱스 추가를 고려해 보세요.삭제되지 않은 레코드만 조회하는 쿼리(
WHERE deleted_at IS NULL)가 많아질 경우, 인덱스가 없으면 풀 스캔이 발생할 수 있습니다. 마이그레이션 스크립트나@Table(indexes = ...)로 인덱스를 추가하는 것을 권장드립니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java` around lines 21 - 22, The BaseCreatedDeletedEntity.deletedAt mapping currently has no index, so queries filtering on deleted_at IS NULL may scan the table. Add an index for the deleted_at column by updating the entity’s `@Table`(indexes = ...) on BaseCreatedDeletedEntity or by adding the index in the migration script, and keep the existing `@Column`(name = "deleted_at") mapping unchanged.
24-26: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win
softDelete()재호출 시 멱등성 체크가 없어요.이미 삭제된 엔티티에
softDelete()를 다시 호출하면deletedAt이 최신 시각으로 덮어씌워집니다. 최초 삭제 시각을 감사 목적으로 보존하려면 가드 조건을 추가하는 게 좋습니다.🛡️ 개선 제안
public void softDelete() { - this.deletedAt = LocalDateTime.now(); + if (this.deletedAt == null) { + this.deletedAt = LocalDateTime.now(); + } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java` around lines 24 - 26, `BaseCreatedDeletedEntity.softDelete()` is not idempotent and overwrites `deletedAt` on repeated calls. Update `softDelete()` to guard against reassigning the timestamp when `deletedAt` is already set, so the first deletion time is preserved for audit purposes. Use the `deletedAt` field in `BaseCreatedDeletedEntity` as the check point and keep the existing method behavior unchanged for not-yet-deleted entities.src/main/java/com/mr/global/entity/BaseTimeDeletedEntity.java (1)
26-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
BaseCreatedDeletedEntity와deletedAt/softDelete()로직이 완전히 중복되네요.
MappedSuperclass는 다중 상속이 불가능해 완전한 통합은 어렵지만, 같은 로직이 두 파일에 그대로 복사된 상태입니다. 인터페이스의 default 메서드로softDelete()를 추출하는 방법도 검토해볼 수 있지만, 필드 접근을 위해 setter를 노출해야 하는 트레이드오프가 있어 지금 구조를 유지해도 무방합니다.또한 이 파일의
softDelete()(Line 29-31)도BaseCreatedDeletedEntity와 동일하게 재호출 시deletedAt이 덮어써지는 멱등성 이슈가 있습니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/mr/global/entity/BaseTimeDeletedEntity.java` around lines 26 - 31, `BaseTimeDeletedEntity.softDelete()` duplicates the same `deletedAt`/`softDelete()` logic found in `BaseCreatedDeletedEntity`, so keep the current structure if needed but consider extracting shared behavior into a common default method or helper where possible. More importantly, make `softDelete()` idempotent by preserving an existing `deletedAt` value instead of overwriting it on repeated calls, and update the `deletedAt` assignment logic in this class accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java`:
- Around line 21-22: The BaseCreatedDeletedEntity.deletedAt mapping currently
has no index, so queries filtering on deleted_at IS NULL may scan the table. Add
an index for the deleted_at column by updating the entity’s `@Table`(indexes =
...) on BaseCreatedDeletedEntity or by adding the index in the migration script,
and keep the existing `@Column`(name = "deleted_at") mapping unchanged.
- Around line 24-26: `BaseCreatedDeletedEntity.softDelete()` is not idempotent
and overwrites `deletedAt` on repeated calls. Update `softDelete()` to guard
against reassigning the timestamp when `deletedAt` is already set, so the first
deletion time is preserved for audit purposes. Use the `deletedAt` field in
`BaseCreatedDeletedEntity` as the check point and keep the existing method
behavior unchanged for not-yet-deleted entities.
In `@src/main/java/com/mr/global/entity/BaseCreatedEntity.java`:
- Around line 1-20: `BaseCreatedEntity`의 `createdAt`이 다른 공통 엔티티들에서도 중복 선언되고
있으므로, 상속 구조를 정리해 중복을 제거하세요. `BaseCreatedEntity`를 공통 최상위로 유지하고 `BaseTimeEntity`는
이를 상속해 `updatedAt`만 추가, `BaseCreatedDeletedEntity`와 `BaseTimeDeletedEntity`도 각각
필요한 필드만 덧붙이도록 구조를 맞추세요. `BaseCreatedEntity`, `BaseTimeEntity`,
`BaseCreatedDeletedEntity`, `BaseTimeDeletedEntity`의 필드 선언과 상속 관계를 함께 수정해
`@CreatedDate` 중복을 없애면 됩니다.
In `@src/main/java/com/mr/global/entity/BaseTimeDeletedEntity.java`:
- Around line 26-31: `BaseTimeDeletedEntity.softDelete()` duplicates the same
`deletedAt`/`softDelete()` logic found in `BaseCreatedDeletedEntity`, so keep
the current structure if needed but consider extracting shared behavior into a
common default method or helper where possible. More importantly, make
`softDelete()` idempotent by preserving an existing `deletedAt` value instead of
overwriting it on repeated calls, and update the `deletedAt` assignment logic in
this class accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 2f14f485-ab62-4ff8-85d2-6e99f1d7b2d4
📒 Files selected for processing (5)
src/main/java/com/mr/Application.javasrc/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.javasrc/main/java/com/mr/global/entity/BaseCreatedEntity.javasrc/main/java/com/mr/global/entity/BaseTimeDeletedEntity.javasrc/main/java/com/mr/global/entity/BaseTimeEntity.java
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java (2)
12-13: 🗄️ Data Integrity & Integration | 🔵 Trivial소프트 삭제 필터링 전략도 함께 고려해보세요.
deletedAt필드는 잘 추가되었지만, 이를 상속하는 엔티티의 리포지토리/쿼리에서 삭제된 레코드를 자동으로 걸러주는 장치(@Where(clause = "deleted_at is null")또는 JPA@SQLRestriction등)가 없습니다. 향후 각 리포지토리에서 매번 조건을 넣지 않으면 삭제된 데이터가 실수로 조회될 위험이 있습니다. 관련 공식 문서: Hibernate@SQLRestriction(구@Where) 애노테이션을 참고하시면 도움이 될 것 같습니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java` around lines 12 - 13, `BaseCreatedDeletedEntity`에 추가된 `deletedAt`만으로는 소프트 삭제가 자동 필터링되지 않으니, 이 베이스 엔티티를 상속하는 조회에서 삭제된 레코드가 기본 제외되도록 Hibernate 필터링을 적용하세요. `deletedAt` 필드가 선언된 `BaseCreatedDeletedEntity`에 `@Where(clause = "deleted_at is null")` 또는 동등한 `@SQLRestriction`를 추가해, 별도 리포지토리/쿼리마다 조건을 반복하지 않아도 되게 수정하면 됩니다.
8-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value소프트 삭제 로직 정확 👍, 다만 중복 코드가 눈에 띄네요.
softDelete()/isDeleted()로직 자체는 정확하고 멱등성도 잘 지켜졌습니다. 다만BaseTimeDeletedEntity에도deletedAt,softDelete(),isDeleted()가 거의 동일하게 반복 구현되어 있습니다 (src/main/java/com/mr/global/entity/BaseTimeDeletedEntity.java:10-24참고).Java는 단일 상속만 지원하므로 필드 상속 구조상 완전한 중복 제거는 어렵지만, 공통 동작을 인터페이스의 default method로 추출하면 유지보수성을 높일 수 있습니다.
♻️ 인터페이스 추출 예시
public interface SoftDeletable { LocalDateTime getDeletedAt(); void setDeletedAt(LocalDateTime deletedAt); default void softDelete() { if (getDeletedAt() == null) { setDeletedAt(LocalDateTime.now()); } } default boolean isDeleted() { return getDeletedAt() != null; } }두 삭제 기반 클래스가 이 인터페이스를 구현하도록 하면 중복을 제거할 수 있습니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java` around lines 8 - 24, `BaseCreatedDeletedEntity` duplicates the same soft-delete behavior already present in `BaseTimeDeletedEntity`; extract the shared `deletedAt`, `softDelete()`, and `isDeleted()` contract into a common `SoftDeletable` interface with default methods, then have both entity base classes implement it while keeping their own field mapping/getter-setter accessors. Use the existing `deletedAt`, `softDelete()`, and `isDeleted()` symbols to align the two classes around the shared behavior and remove the repeated method bodies.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.java`:
- Around line 12-13: `BaseCreatedDeletedEntity`에 추가된 `deletedAt`만으로는 소프트 삭제가 자동
필터링되지 않으니, 이 베이스 엔티티를 상속하는 조회에서 삭제된 레코드가 기본 제외되도록 Hibernate 필터링을 적용하세요.
`deletedAt` 필드가 선언된 `BaseCreatedDeletedEntity`에 `@Where(clause = "deleted_at is
null")` 또는 동등한 `@SQLRestriction`를 추가해, 별도 리포지토리/쿼리마다 조건을 반복하지 않아도 되게 수정하면 됩니다.
- Around line 8-24: `BaseCreatedDeletedEntity` duplicates the same soft-delete
behavior already present in `BaseTimeDeletedEntity`; extract the shared
`deletedAt`, `softDelete()`, and `isDeleted()` contract into a common
`SoftDeletable` interface with default methods, then have both entity base
classes implement it while keeping their own field mapping/getter-setter
accessors. Use the existing `deletedAt`, `softDelete()`, and `isDeleted()`
symbols to align the two classes around the shared behavior and remove the
repeated method bodies.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 27dc568d-fea3-4b23-b477-afbec564cb46
📒 Files selected for processing (3)
src/main/java/com/mr/global/entity/BaseCreatedDeletedEntity.javasrc/main/java/com/mr/global/entity/BaseTimeDeletedEntity.javasrc/main/java/com/mr/global/entity/BaseTimeEntity.java
rkdehdrbs7885-oss
left a comment
There was a problem hiding this comment.
그동안 BaseEntity는 전부 하나에 묶는 형식만 봤었는데, 이런 식으로도 할 수 있다는 걸 배웠습니다!
📍 개요
BaseEntity 4종류를 추가했습니다.
⛓️💥 관련 이슈
🛠️ 작업 내용
🔥 리뷰 요청 사항
X
✅ 체크리스트
📎 참고 사항
X
Summary by CodeRabbit
created_at, 수정 시각updated_at).deleted_at유무로 확인할 수 있습니다.