diff --git a/src/main/java/in/koreatech/koin/domain/timetable/controller/TimetableController.java b/src/main/java/in/koreatech/koin/domain/timetable/controller/TimetableController.java index e9ebdf4ec..f6d58464e 100644 --- a/src/main/java/in/koreatech/koin/domain/timetable/controller/TimetableController.java +++ b/src/main/java/in/koreatech/koin/domain/timetable/controller/TimetableController.java @@ -89,5 +89,4 @@ public ResponseEntity deleteTimetableById( timetableService.deleteTimetableLecture(userId, timetableId); return ResponseEntity.ok().build(); } - } diff --git a/src/main/java/in/koreatech/koin/domain/timetable/model/Lecture.java b/src/main/java/in/koreatech/koin/domain/timetable/model/Lecture.java index 4966250c7..0d558701c 100644 --- a/src/main/java/in/koreatech/koin/domain/timetable/model/Lecture.java +++ b/src/main/java/in/koreatech/koin/domain/timetable/model/Lecture.java @@ -5,8 +5,11 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -24,11 +27,6 @@ public class Lecture { @GeneratedValue(strategy = IDENTITY) private Integer id; - @Size(max = 255) - @NotNull - @Column(name = "semester_date", nullable = false) - private String semester; - @Size(max = 255) @NotNull @Column(name = "code", nullable = false) @@ -86,17 +84,21 @@ public class Lecture { @Column(name = "class_time", nullable = false) private String classTime; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "semester_id") + private Semester semester; + @Builder - private Lecture( - String code, String semester, - String name, String grades, String lectureClass, + public Lecture( + String code, String name, + String grades, String lectureClass, String regularNumber, String department, String target, String professor, String isEnglish, String designScore, - String isElearning, String classTime + String isElearning, String classTime, + Semester semester ) { this.code = code; - this.semester = semester; this.name = name; this.grades = grades; this.lectureClass = lectureClass; @@ -108,5 +110,6 @@ private Lecture( this.designScore = designScore; this.isElearning = isElearning; this.classTime = classTime; + this.semester = semester; } } diff --git a/src/main/java/in/koreatech/koin/domain/timetable/model/Semester.java b/src/main/java/in/koreatech/koin/domain/timetable/model/Semester.java index 8f42c0a75..a219d6670 100644 --- a/src/main/java/in/koreatech/koin/domain/timetable/model/Semester.java +++ b/src/main/java/in/koreatech/koin/domain/timetable/model/Semester.java @@ -3,10 +3,14 @@ import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; +import java.util.ArrayList; +import java.util.List; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -29,8 +33,12 @@ public class Semester { @Column(name = "semester", nullable = false, unique = true) private String semester; + @OneToMany(mappedBy = "semester") + private List lectures = new ArrayList<>(); + @Builder - private Semester(String semester) { + public Semester(String semester, List lectures) { this.semester = semester; + this.lectures = lectures; } } diff --git a/src/main/java/in/koreatech/koin/domain/timetable/repository/LectureRepository.java b/src/main/java/in/koreatech/koin/domain/timetable/repository/LectureRepository.java index 64235b95f..8525b4e9b 100644 --- a/src/main/java/in/koreatech/koin/domain/timetable/repository/LectureRepository.java +++ b/src/main/java/in/koreatech/koin/domain/timetable/repository/LectureRepository.java @@ -8,20 +8,21 @@ import in.koreatech.koin.domain.timetable.exception.LectureNotFoundException; import in.koreatech.koin.domain.timetable.exception.SemesterNotFoundException; import in.koreatech.koin.domain.timetable.model.Lecture; +import in.koreatech.koin.domain.timetable.model.Semester; public interface LectureRepository extends Repository { - List findBySemester(String semesterDate); + List findBySemester(Semester semester); Lecture save(Lecture lecture); Optional findById(Integer id); - Optional findBySemesterAndCodeAndLectureClass(String semesterDate, String code, String classLecture); + Optional findBySemesterAndCodeAndLectureClass(Semester semester, String code, String classLecture); - default Lecture getBySemesterAndCodeAndLectureClass(String semesterDate, String code, String classLecture) { - return findBySemesterAndCodeAndLectureClass(semesterDate, code, classLecture) - .orElseThrow(() -> SemesterNotFoundException.withDetail("semester: " + semesterDate + " code: " + code + " classLecture: " + classLecture)); + default Lecture getBySemesterAndCodeAndLectureClass(Semester semester, String code, String classLecture) { + return findBySemesterAndCodeAndLectureClass(semester, code, classLecture) + .orElseThrow(() -> SemesterNotFoundException.withDetail("semester: " + semester.getSemester() + " code: " + code + " classLecture: " + classLecture)); } default Lecture getLectureById(Integer id) { diff --git a/src/main/java/in/koreatech/koin/domain/timetable/service/TimetableService.java b/src/main/java/in/koreatech/koin/domain/timetable/service/TimetableService.java index 1727395d3..1332ecfdb 100644 --- a/src/main/java/in/koreatech/koin/domain/timetable/service/TimetableService.java +++ b/src/main/java/in/koreatech/koin/domain/timetable/service/TimetableService.java @@ -41,8 +41,8 @@ public class TimetableService { private final UserRepository userRepository; private final EntityManager entityManager; - public List getLecturesBySemester(String semester) { - semesterRepositoryV2.getBySemester(semester); + public List getLecturesBySemester(String requestSemester) { + Semester semester = semesterRepositoryV2.getBySemester(requestSemester); List lectures = lectureRepositoryV2.findBySemester(semester); return lectures.stream() .map(LectureResponse::from) @@ -57,7 +57,7 @@ public TimetableResponse createTimetables(Integer userId, TimetableCreateRequest semester.getId()); for (TimetableCreateRequest.InnerTimetableRequest timeTable : request.timetable()) { - Lecture lecture = lectureRepositoryV2.getBySemesterAndCodeAndLectureClass(request.semester(), + Lecture lecture = lectureRepositoryV2.getBySemesterAndCodeAndLectureClass(semester, timeTable.code(), timeTable.lectureClass()); TimetableLecture timetableLecture = TimetableLecture.builder() .classPlace(timeTable.classPlace()) diff --git a/src/main/java/in/koreatech/koin/domain/timetableV2/repository/LectureRepositoryV2.java b/src/main/java/in/koreatech/koin/domain/timetableV2/repository/LectureRepositoryV2.java index 4c20a98be..5a3d3c0a9 100644 --- a/src/main/java/in/koreatech/koin/domain/timetableV2/repository/LectureRepositoryV2.java +++ b/src/main/java/in/koreatech/koin/domain/timetableV2/repository/LectureRepositoryV2.java @@ -8,21 +8,22 @@ import in.koreatech.koin.domain.timetable.exception.LectureNotFoundException; import in.koreatech.koin.domain.timetable.exception.SemesterNotFoundException; import in.koreatech.koin.domain.timetable.model.Lecture; +import in.koreatech.koin.domain.timetable.model.Semester; public interface LectureRepositoryV2 extends Repository { - List findBySemester(String semesterDate); + List findBySemester(Semester semester); Lecture save(Lecture lecture); Optional findById(Integer id); - Optional findBySemesterAndCodeAndLectureClass(String semesterDate, String code, String classLecture); + Optional findBySemesterAndCodeAndLectureClass(Semester semester, String code, String classLecture); - default Lecture getBySemesterAndCodeAndLectureClass(String semesterDate, String code, String classLecture) { - return findBySemesterAndCodeAndLectureClass(semesterDate, code, classLecture) + default Lecture getBySemesterAndCodeAndLectureClass(Semester semester, String code, String classLecture) { + return findBySemesterAndCodeAndLectureClass(semester, code, classLecture) .orElseThrow(() -> SemesterNotFoundException.withDetail( - "semester: " + semesterDate + " code: " + code + " classLecture: " + classLecture)); + "semester: " + semester.getSemester() + " code: " + code + " classLecture: " + classLecture)); } default Lecture getLectureById(Integer id) { diff --git a/src/main/resources/db/migration/V103__alter_lecture_class_time.sql b/src/main/resources/db/migration/V103__alter_lecture_class_time.sql new file mode 100644 index 000000000..eba35ad70 --- /dev/null +++ b/src/main/resources/db/migration/V103__alter_lecture_class_time.sql @@ -0,0 +1,2 @@ +ALTER TABLE `koin`.`lectures` +MODIFY COLUMN `class_time` VARCHAR(255) NOT NULL; diff --git a/src/main/resources/db/migration/V104__alter_lecture_class_semester_fk.sql b/src/main/resources/db/migration/V104__alter_lecture_class_semester_fk.sql new file mode 100644 index 000000000..1fce44db3 --- /dev/null +++ b/src/main/resources/db/migration/V104__alter_lecture_class_semester_fk.sql @@ -0,0 +1,13 @@ +ALTER TABLE `koin`.`lectures` + ADD COLUMN `semester_id` INT UNSIGNED NOT NULL; + +UPDATE `koin`.`lectures` l +SET `semester_id` = (SELECT `id` + FROM `koin`.`semester` s + WHERE l.`semester_date` = s.`semester`); + +ALTER TABLE `koin`.`lectures` + ADD CONSTRAINT `FK_LECTURES_ON_SEMESTER` + FOREIGN KEY (`semester_id`) + REFERENCES `koin`.`semester` (`id`) + ON UPDATE CASCADE; diff --git a/src/main/resources/db/migration/V105__alter_lecture_drop_semester_date_column.sql b/src/main/resources/db/migration/V105__alter_lecture_drop_semester_date_column.sql new file mode 100644 index 000000000..d36bd9fe8 --- /dev/null +++ b/src/main/resources/db/migration/V105__alter_lecture_drop_semester_date_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE `koin`.`lectures` +DROP COLUMN `semester_date`; diff --git a/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java b/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java index 105a5c35f..2b923f23f 100644 --- a/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/TimetableApiTest.java @@ -48,15 +48,14 @@ void setup() { @Test void 특정_학기_강의를_조회한다() throws Exception { - semesterFixture.semester("20192"); - semesterFixture.semester("20201"); - String semester = "20201"; + Semester semester1 = semesterFixture.semester("20192"); + Semester semester = semesterFixture.semester("20201"); lectureFixture.HRD_개론(semester); - lectureFixture.건축구조의_이해_및_실습("20192"); + lectureFixture.건축구조의_이해_및_실습(semester1); mockMvc.perform( get("/lectures") - .param("semester_date", semester) + .param("semester_date", semester.getSemester()) .contentType(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) @@ -85,15 +84,14 @@ void setup() { @Test void 특정_학기_강의들을_조회한다() throws Exception { - semesterFixture.semester("20201"); - String semester = "20201"; + Semester semester = semesterFixture.semester("20201"); lectureFixture.HRD_개론(semester); lectureFixture.건축구조의_이해_및_실습(semester); lectureFixture.재료역학(semester); mockMvc.perform( get("/lectures") - .param("semester_date", semester) + .param("semester_date", semester.getSemester()) .contentType(MediaType.APPLICATION_JSON) ) .andExpect(status().isOk()) @@ -156,7 +154,7 @@ void setup() { @Test void 존재하지_않는_학기를_조회하면_404() throws Exception { - String semester = "20201"; + Semester semester = semesterFixture.semester("20201"); lectureFixture.HRD_개론(semester); lectureFixture.건축구조의_이해_및_실습(semester); @@ -239,8 +237,8 @@ void setup() { String token = userFixture.getToken(user); Semester semester = semesterFixture.semester("20192"); - Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester.getSemester()); - Lecture HRD_개론 = lectureFixture.HRD_개론(semester.getSemester()); + Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester); + Lecture HRD_개론 = lectureFixture.HRD_개론(semester); timetableV2Fixture.시간표6(user, semester, 건축구조의_이해_및_실습, HRD_개론); @@ -322,8 +320,8 @@ void setup() { String token = userFixture.getToken(user); Semester semester1 = semesterFixture.semester("20192"); Semester semester2 = semesterFixture.semester("20201"); - Lecture HRD_개론 = lectureFixture.HRD_개론(semester1.getSemester()); - Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester2.getSemester()); + Lecture HRD_개론 = lectureFixture.HRD_개론(semester1); + Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester2); timetableV2Fixture.시간표6(user, semester1, HRD_개론, null); timetableV2Fixture.시간표6(user, semester2, 건축구조의_이해_및_실습, null); @@ -350,8 +348,8 @@ void setup() { String token = userFixture.getToken(user); Semester semester = semesterFixture.semester("20192"); - lectureFixture.건축구조의_이해_및_실습(semester.getSemester()); - lectureFixture.HRD_개론(semester.getSemester()); + lectureFixture.건축구조의_이해_및_실습(semester); + lectureFixture.HRD_개론(semester); timetableV2Fixture.시간표1(user, semester); @@ -443,8 +441,8 @@ void setup() { String token = userFixture.getToken(user); Semester semester = semesterFixture.semester("20192"); - lectureFixture.건축구조의_이해_및_실습(semester.getSemester()); - lectureFixture.HRD_개론(semester.getSemester()); + lectureFixture.건축구조의_이해_및_실습(semester); + lectureFixture.HRD_개론(semester); timetableV2Fixture.시간표1(user, semester); @@ -550,8 +548,8 @@ void setup() { String token = userFixture.getToken(user); Semester semester = semesterFixture.semester("20192"); - Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester.getSemester()); - Lecture HRD_개론 = lectureFixture.HRD_개론(semester.getSemester()); + Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester); + Lecture HRD_개론 = lectureFixture.HRD_개론(semester); timetableV2Fixture.시간표6(user, semester, 건축구조의_이해_및_실습, HRD_개론); diff --git a/src/test/java/in/koreatech/koin/acceptance/TimetableV2ApiTest.java b/src/test/java/in/koreatech/koin/acceptance/TimetableV2ApiTest.java index 2b041c2c7..d422702be 100644 --- a/src/test/java/in/koreatech/koin/acceptance/TimetableV2ApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/TimetableV2ApiTest.java @@ -178,7 +178,7 @@ void setup() { User user = userFixture.준호_학생().getUser(); String token = userFixture.getToken(user); Semester semester = semesterFixture.semester("20192"); - Lecture lecture = lectureFixture.HRD_개론(semester.getSemester()); + Lecture lecture = lectureFixture.HRD_개론(semester); TimetableFrame frame1 = timetableV2Fixture.시간표5(user, semester, lecture); @@ -425,8 +425,8 @@ void setup() { String token = userFixture.getToken(user); Semester semester = semesterFixture.semester("20192"); - Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester.getSemester()); - Lecture HRD_개론 = lectureFixture.HRD_개론(semester.getSemester()); + Lecture 건축구조의_이해_및_실습 = lectureFixture.건축구조의_이해_및_실습(semester); + Lecture HRD_개론 = lectureFixture.HRD_개론(semester); TimetableFrame frame = timetableV2Fixture.시간표6(user, semester, 건축구조의_이해_및_실습, HRD_개론); @@ -485,8 +485,8 @@ void setup() { User user1 = userFixture.준호_학생().getUser(); String token = userFixture.getToken(user1); Semester semester = semesterFixture.semester("20192"); - Lecture lecture1 = lectureFixture.HRD_개론("20192"); - Lecture lecture2 = lectureFixture.영어청해("20192"); + Lecture lecture1 = lectureFixture.HRD_개론(semester); + Lecture lecture2 = lectureFixture.영어청해(semester); TimetableFrame frame = timetableV2Fixture.시간표4(user1, semester, lecture1, lecture2); Integer lectureId = lecture1.getId(); @@ -505,8 +505,8 @@ void setup() { User user1 = userFixture.준호_학생().getUser(); String token = userFixture.getToken(user1); Semester semester = semesterFixture.semester("20192"); - Lecture lecture1 = lectureFixture.HRD_개론("20192"); - Lecture lecture2 = lectureFixture.영어청해("20192"); + Lecture lecture1 = lectureFixture.HRD_개론(semester); + Lecture lecture2 = lectureFixture.영어청해(semester); TimetableFrame frame = timetableV2Fixture.시간표4(user1, semester, lecture1, lecture2); Integer frameId = frame.getId(); @@ -525,8 +525,8 @@ void setup() { User user1 = userFixture.준호_학생().getUser(); String token = userFixture.getToken(user1); Semester semester = semesterFixture.semester("20192"); - Lecture lecture1 = lectureFixture.HRD_개론("20192"); - Lecture lecture2 = lectureFixture.영어청해("20192"); + Lecture lecture1 = lectureFixture.HRD_개론(semester); + Lecture lecture2 = lectureFixture.영어청해(semester); TimetableFrame frame = timetableV2Fixture.시간표4(user1, semester, lecture1, lecture2); List timetableLectureIds = frame.getTimetableLectures().stream() diff --git a/src/test/java/in/koreatech/koin/fixture/LectureFixture.java b/src/test/java/in/koreatech/koin/fixture/LectureFixture.java index 172d9ffd4..556e56aba 100644 --- a/src/test/java/in/koreatech/koin/fixture/LectureFixture.java +++ b/src/test/java/in/koreatech/koin/fixture/LectureFixture.java @@ -3,6 +3,7 @@ import org.springframework.stereotype.Component; import in.koreatech.koin.domain.timetable.model.Lecture; +import in.koreatech.koin.domain.timetable.model.Semester; import in.koreatech.koin.domain.timetable.repository.LectureRepository; @Component @@ -15,7 +16,7 @@ public LectureFixture(LectureRepository lectureRepository) { this.lectureRepository = lectureRepository; } - public Lecture 건축구조의_이해_및_실습(String semester) { + public Lecture 건축구조의_이해_및_실습(Semester semester) { return lectureRepository.save( Lecture.builder() .code("ARB244") @@ -35,7 +36,7 @@ public LectureFixture(LectureRepository lectureRepository) { ); } - public Lecture HRD_개론(String semester) { + public Lecture HRD_개론(Semester semester) { return lectureRepository.save( Lecture.builder() .code("BSM590") @@ -55,7 +56,7 @@ public LectureFixture(LectureRepository lectureRepository) { ); } - public Lecture 재료역학(String semester) { + public Lecture 재료역학(Semester semester) { return lectureRepository.save( Lecture.builder() .code("MEB311") @@ -75,7 +76,7 @@ public LectureFixture(LectureRepository lectureRepository) { ); } - public Lecture 영어청해(String semester) { + public Lecture 영어청해(Semester semester) { return lectureRepository.save( Lecture.builder() .code("LAN324")