Skip to content

fix: 유닛 & 파일 중간테이블 생성#383

Merged
jickDo merged 1 commit intodevfrom
fix/382-create-episodefileresourcemapping-table
Aug 27, 2025
Merged

fix: 유닛 & 파일 중간테이블 생성#383
jickDo merged 1 commit intodevfrom
fix/382-create-episodefileresourcemapping-table

Conversation

@jickDo
Copy link
Copy Markdown
Contributor

@jickDo jickDo commented Aug 27, 2025

개요

코드상에는 파일과 유닛간 중간테이블 조회 로직이 있는데 실제 테이블이 없어서 발생하는 문제 해결

작업 내용

  • 엔티티 테이블 매핑 이름 선언적 생성
  • flyway파일 추가

Closes #382

Summary by CodeRabbit

  • Chores
    • 에피소드와 파일 리소스 연결을 위한 신규 데이터베이스 매핑 구조를 도입하고 마이그레이션을 추가했습니다.
    • 생성/수정 시각 자동 기록 및 외래키 제약으로 데이터 무결성과 추적성을 강화했습니다.
    • 사용자 화면이나 기능 동작에는 변화가 없으며 기존 데이터에 영향 없습니다.
    • 배포 후 추가 조치 필요 없고, 향후 관련 기능 확장을 위한 기반을 정비했습니다.

@jickDo jickDo self-assigned this Aug 27, 2025
@jickDo jickDo linked an issue Aug 27, 2025 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 27, 2025

Walkthrough

EpisodeFileResourceMapping 엔티티에 @table 애너테이션을 추가하고, 해당 테이블을 생성하는 DB 마이그레이션(V33)을 도입하여 스키마에 episode_file_resource_mapping 테이블을 생성한다. 외래키로 episodes(id), file_resources(id)를 참조한다.

Changes

Cohort / File(s) Summary
JPA 엔티티 매핑 명시
src/main/java/.../EpisodeFileResourceMapping.java
엔티티에 @Table(name="episode_file_resource_mapping") 추가. 기존 매핑과 로직 변경 없음.
DB 마이그레이션 추가
src/main/resources/db/migration/V33__add_episode_file_resource_mapping.sql
episode_file_resource_mapping 테이블 생성: id, episode_id, file_resource_id, created_at, updated_at 및 두 외래키 제약 추가.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Assessment against linked issues

Objective Addressed Explanation
테이블 생성 [#382]
연관로직 정상 시행 확인 [#382] 코드 변경만으로는 연관 로직의 동작 확인 여부를 판단할 수 없음 (테스트/사용처 변경 미포함).

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 Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/382-create-episodefileresourcemapping-table

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@jickDo jickDo merged commit 5a68dd8 into dev Aug 27, 2025
1 of 2 checks passed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between af1c335 and c1e39ac.

📒 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” 정책을 결정하고, 마이그레이션·엔티티·서비스 로직 간 삭제 동작이 일관되도록 맞춰 주세요.

Comment on lines +1 to +10
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +6 to +7
created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '생성일시',
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '수정일시',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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*.java

Length 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과 엔티티 매핑을 일치시키시기 바랍니다.

@jickDo jickDo deleted the fix/382-create-episodefileresourcemapping-table branch August 28, 2025 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] episodeFileResourceMapping 테이블이 없는문제

1 participant