Conversation
WalkthroughEpisodeFileResourceMapping 엔티티에 @table 애너테이션을 추가하고, 해당 테이블을 생성하는 DB 마이그레이션(V33)을 도입하여 스키마에 episode_file_resource_mapping 테이블을 생성한다. 외래키로 episodes(id), file_resources(id)를 참조한다. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Assessment against linked issues
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/com/unretired/core/curriculum/domain/EpisodeFileResourceMapping.java (1)
25-33: 조인 컬럼 명시 + 유니크/인덱스 보강을 엔티티에도 반영 권장DDL과의 이름 불일치 리스크를 없애기 위해 @joincolumn으로 FK 컬럼명을 고정하고, UNIQUE/INDEX를 @table에도 기술해 두면 가독성과 일관성이 좋아집니다.
@@ -@Table(name="episode_file_resource_mapping") +@Table( + name = "episode_file_resource_mapping", + uniqueConstraints = @UniqueConstraint(name = "uk_efrm_episode_file", columnNames = {"episode_id","file_resource_id"}), + indexes = { + @Index(name = "idx_efrm_episode_id", columnList = "episode_id"), + @Index(name = "idx_efrm_file_resource_id", columnList = "file_resource_id") + } +) public class EpisodeFileResourceMapping extends BaseEntity { @@ - @ManyToOne(fetch = FetchType.LAZY) - private Episode episode; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "episode_id", nullable = false, foreignKey = @ForeignKey(name = "fk_efrm_episode")) + private Episode episode; @@ - @ManyToOne(fetch = FetchType.LAZY) - private FileResource fileResource; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "file_resource_id", nullable = false, foreignKey = @ForeignKey(name = "fk_efrm_file_resource")) + private FileResource fileResource;추가 필요한 import:
import jakarta.persistence.Index; import jakarta.persistence.JoinColumn; import jakarta.persistence.ForeignKey; import jakarta.persistence.UniqueConstraint;
🧹 Nitpick comments (1)
src/main/resources/db/migration/V33__add_episode_file_resource_mapping.sql (1)
1-1: Flyway에서는 CREATE TABLE IF NOT EXISTS 지양 권장스키마 드리프트를 숨길 수 있으니 실패로 드러나게 두는 편이 안전합니다. 중복 생성 위험이 없다면 IF NOT EXISTS 제거를 권장합니다.
-CREATE TABLE IF NOT EXISTS episode_file_resource_mapping +CREATE TABLE episode_file_resource_mapping
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/com/unretired/core/curriculum/domain/EpisodeFileResourceMapping.java(2 hunks)src/main/resources/db/migration/V33__add_episode_file_resource_mapping.sql(1 hunks)
🔇 Additional comments (3)
src/main/resources/db/migration/V33__add_episode_file_resource_mapping.sql (1)
1-10: MySQL 전용 마이그레이션 구문 사용 확인 필요
현재V33__add_episode_file_resource_mapping.sql뿐 아니라 기존 모든 마이그레이션(V1~V32)에서도AUTO_INCREMENT,ON UPDATE CURRENT_TIMESTAMP,COMMENT등 MySQL 전용 문법을 사용하고 있습니다. 운영 DB가 MySQL이 아니라면 마이그레이션 실행 시 오류가 발생할 수 있으니, 아래 사항을 꼭 검토해 주세요.
- 운영(production) 환경의 실제 DB 벤더 확인
application.yml/application-*.properties, CI/CD·Docker 설정 등에서spring.datasource.url·hibernate.dialect·spring.flyway.*등 DB 연결 및 벤더 관련 설정 검토- 테스트 환경의 H2 데이터베이스가 MySQL 호환 모드(
jdbc:h2:mem:testdb;MODE=MySQL)로 설정되어 있는지 확인src/main/java/com/unretired/core/curriculum/domain/EpisodeFileResourceMapping.java (2)
13-13: 엔티티-테이블 명시 매핑 추가: 좋습니다@table(name="episode_file_resource_mapping") 도입으로 엔티티와 테이블 매핑이 명확해졌습니다.
Also applies to: 25-25
30-33: 삭제 전파 정책 결정 및 설정 일치화 필요현재 확인 결과,
episode_file_resource_mapping테이블의 외래 키에는 ON DELETE CASCADE가 설정되어 있지 않으며, 엔티티에도 별도의 Cascade 설정이 없습니다. 대신 서비스 레이어에서 매핑을 수동으로 삭제하고 있으므로, 아래 사항을 검토해 주세요.
- DB 마이그레이션(
V33__add_episode_file_resource_mapping.sql)
•FOREIGN KEY (episode_id) REFERENCES episodes(id)
•FOREIGN KEY (file_resource_id) REFERENCES file_resources(id)
→ ON DELETE CASCADE 적용 필요 여부 결정- JPA 엔티티 매핑
•Episode/FileResource엔티티의 OneToMany 측에 cascade=CascadeType.REMOVE 및 orphanRemoval=true 추가 검토
• ManyToOne 측의 Cascade 설정은 일반적으로 부모 삭제 시 자식까지 전파되도록 하지 않으므로, 위 방향으로 설정을 맞출지 결정- 서비스 레이어 수동 삭제 로직
•CurriculumCRUDServiceImpl.deleteEpisode()및deleteFileResource()내 매핑 삭제 코드와 충돌 여부 확인
• DB 또는 JPA 레벨 삭제 정책 변경 시 해당 로직의 중복/불필요 코드 제거 검토위 내용을 바탕으로 “DB 레벨 ON DELETE CASCADE vs. JPA Cascade” 정책을 결정하고, 마이그레이션·엔티티·서비스 로직 간 삭제 동작이 일관되도록 맞춰 주세요.
| CREATE TABLE IF NOT EXISTS episode_file_resource_mapping | ||
| ( | ||
| id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY COMMENT '매핑 고유 ID', | ||
| episode_id BIGINT NOT NULL COMMENT '에피소드 ID', | ||
| file_resource_id BIGINT NOT NULL COMMENT '파일 리소스 ID', | ||
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시', | ||
| updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시', | ||
| FOREIGN KEY (episode_id) REFERENCES episodes(id), | ||
| FOREIGN KEY (file_resource_id) REFERENCES file_resources(id) | ||
| ); No newline at end of file |
There was a problem hiding this comment.
🛠️ Refactor suggestion
중복 매핑 방지 + 조회 성능 강화를 위한 제약/인덱스 추가 제안
매핑 테이블 특성상 (episode_id, file_resource_id)의 중복을 방지하는 UNIQUE 제약과 FK 컬럼 인덱스가 필요합니다. 또한 삭제 전파가 필요하면 FK에 ON DELETE CASCADE를 명시하세요.
아래와 같이 보완을 권장합니다:
-CREATE TABLE IF NOT EXISTS episode_file_resource_mapping
+CREATE TABLE IF NOT EXISTS episode_file_resource_mapping
(
id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY COMMENT '매핑 고유 ID',
episode_id BIGINT NOT NULL COMMENT '에피소드 ID',
file_resource_id BIGINT NOT NULL COMMENT '파일 리소스 ID',
- created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시',
- updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시',
- FOREIGN KEY (episode_id) REFERENCES episodes(id),
- FOREIGN KEY (file_resource_id) REFERENCES file_resources(id)
+ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시',
+ updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시',
+ CONSTRAINT uk_efrm_episode_file UNIQUE (episode_id, file_resource_id),
+ INDEX idx_efrm_episode_id (episode_id),
+ INDEX idx_efrm_file_resource_id (file_resource_id),
+ CONSTRAINT fk_efrm_episode FOREIGN KEY (episode_id) REFERENCES episodes(id) ON DELETE CASCADE,
+ CONSTRAINT fk_efrm_file_resource FOREIGN KEY (file_resource_id) REFERENCES file_resources(id) ON DELETE CASCADE
);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| CREATE TABLE IF NOT EXISTS episode_file_resource_mapping | |
| ( | |
| id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY COMMENT '매핑 고유 ID', | |
| episode_id BIGINT NOT NULL COMMENT '에피소드 ID', | |
| file_resource_id BIGINT NOT NULL COMMENT '파일 리소스 ID', | |
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시', | |
| updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시', | |
| FOREIGN KEY (episode_id) REFERENCES episodes(id), | |
| FOREIGN KEY (file_resource_id) REFERENCES file_resources(id) | |
| ); | |
| CREATE TABLE IF NOT EXISTS episode_file_resource_mapping | |
| ( | |
| id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY COMMENT '매핑 고유 ID', | |
| episode_id BIGINT NOT NULL COMMENT '에피소드 ID', | |
| file_resource_id BIGINT NOT NULL COMMENT '파일 리소스 ID', | |
| created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시', | |
| updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시', | |
| CONSTRAINT uk_efrm_episode_file UNIQUE (episode_id, file_resource_id), | |
| INDEX idx_efrm_episode_id (episode_id), | |
| INDEX idx_efrm_file_resource_id (file_resource_id), | |
| CONSTRAINT fk_efrm_episode FOREIGN KEY (episode_id) REFERENCES episodes(id) ON DELETE CASCADE, | |
| CONSTRAINT fk_efrm_file_resource FOREIGN KEY (file_resource_id) REFERENCES file_resources(id) ON DELETE CASCADE | |
| ); |
🤖 Prompt for AI Agents
In src/main/resources/db/migration/V33__add_episode_file_resource_mapping.sql
around lines 1 to 10, the migration lacks a UNIQUE constraint to prevent
duplicate (episode_id, file_resource_id) mappings, doesn't explicitly create
indexes on the FK columns for query performance, and omits cascade behavior on
deletes; update the CREATE TABLE to add a UNIQUE constraint on (episode_id,
file_resource_id) (with a descriptive name), ensure indexes exist on episode_id
and file_resource_id (or rely on FK index creation explicitly), and if you want
deletions to cascade, add ON DELETE CASCADE to the foreign key definitions (or
use NO ACTION if you don't want cascade), naming constraints consistently for
clarity.
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시', | ||
| updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시', |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
BaseEntity와 컬럼명/타입 일치 여부 확인
BaseEntity의 createdAt/updatedAt 매핑(@column name, 타입)과 본 DDL(created_at DATETIME)이 일치하는지 확인 바랍니다. 불일치 시 DDL 또는 엔티티 중 한쪽을 맞춰야 합니다.
🏁 Script executed:
#!/bin/bash
# BaseEntity 정의와 컬럼명 확인
rg -nC3 'class\s+BaseEntity\b' src/main/java
rg -nC2 -e 'createdAt|updatedAt|@Column' src/main/java/com/unretired/**/BaseEntity*.javaLength of output: 845
확인: BaseEntity의 createdAt/updatedAt 매핑과 DDL 일치 여부 검토 요청
BaseEntity 엔티티의 생성·수정 시각 필드 매핑(@CreatedDate/@LastModifiedDate, @Column(name=…) 등)과 아래 Migration DDL의 컬럼명이 일치하는지 확인 바랍니다.
현재 DDL에서는
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시',로 정의되어 있으나, BaseEntity에는 createdAt 필드는 존재하더라도 updatedAt 필드나 @Column(name="updated_at") 매핑이 확인되지 않습니다.
필요 조치:
- BaseEntity에
updatedAt필드(@LastModifiedDate) 및@Column(name="updated_at")매핑 추가
또는 - DDL에서
updated_at→ 엔티티가 사용하는 컬럼명(update_time등)으로 수정
위 중 한 가지를 선택하여 DDL과 엔티티 매핑을 일치시키시기 바랍니다.
개요
코드상에는 파일과 유닛간 중간테이블 조회 로직이 있는데 실제 테이블이 없어서 발생하는 문제 해결
작업 내용
Closes #382
Summary by CodeRabbit