diff --git a/src/main/java/io/oduck/api/domain/admin/controller/AdminController.java b/src/main/java/io/oduck/api/domain/admin/controller/AdminController.java index aff35766..d7b7711d 100644 --- a/src/main/java/io/oduck/api/domain/admin/controller/AdminController.java +++ b/src/main/java/io/oduck/api/domain/admin/controller/AdminController.java @@ -149,6 +149,7 @@ public ResponseEntity patchAnimeStudios( return ResponseEntity.noContent().build(); } + // 애니의 성우 수정 @PatchMapping("/animes/{animeId}/voice-actors") public ResponseEntity patchAnimeVoiceActors( diff --git a/src/main/java/io/oduck/api/domain/anime/dto/AnimeReq.java b/src/main/java/io/oduck/api/domain/anime/dto/AnimeReq.java index 26c5a6b9..a49b0a42 100644 --- a/src/main/java/io/oduck/api/domain/anime/dto/AnimeReq.java +++ b/src/main/java/io/oduck/api/domain/anime/dto/AnimeReq.java @@ -19,11 +19,11 @@ public class AnimeReq { @Getter public static class PostReq { @NotBlank - @Length(min = 1, max = 50, message = "글자 수는 0~50을 허용합니다.") + @Length(min = 1, max = 50, message = "글자 수는 1~50을 허용합니다.") private String title; @NotBlank - @Length(min = 1, max = 255, message = "글자 수는 0~255를 허용합니다.") + @Length(min = 1, max = 600, message = "글자 수는 1~600자를 허용합니다.") private String summary; @NotNull diff --git a/src/main/java/io/oduck/api/domain/anime/entity/Anime.java b/src/main/java/io/oduck/api/domain/anime/entity/Anime.java index ec234fe7..7a58b6b1 100644 --- a/src/main/java/io/oduck/api/domain/anime/entity/Anime.java +++ b/src/main/java/io/oduck/api/domain/anime/entity/Anime.java @@ -157,6 +157,12 @@ public void decreaseStarRatingScore(int score){ } public void delete() { + this.animeOriginalAuthors.clear(); + this.animeVoiceActors.clear(); + this.animeGenres.clear(); + this.animeStudios.clear(); + this.series = null; + this.deletedAt = LocalDateTime.now(); } diff --git a/src/main/java/io/oduck/api/domain/genre/entity/Genre.java b/src/main/java/io/oduck/api/domain/genre/entity/Genre.java index 7bc3764c..bd39d302 100644 --- a/src/main/java/io/oduck/api/domain/genre/entity/Genre.java +++ b/src/main/java/io/oduck/api/domain/genre/entity/Genre.java @@ -1,12 +1,17 @@ package io.oduck.api.domain.genre.entity; +import io.oduck.api.domain.anime.entity.AnimeGenre; import io.oduck.api.global.audit.BaseEntity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -22,14 +27,19 @@ public class Genre extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, length = 15, unique = true) + @Column(nullable = false, length = 15) private String name; + @OneToMany(mappedBy = "genre", cascade = CascadeType.PERSIST, orphanRemoval = true) + @Builder.Default + private List animeGenres = new ArrayList<>(); + public void update(String name) { this.name = name; } public void delete() { + this.animeGenres.clear(); this.deletedAt = LocalDateTime.now(); } } \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepository.java b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepository.java index 246deaf6..660abe35 100644 --- a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepository.java +++ b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepository.java @@ -4,12 +4,13 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -public interface GenreRepository extends JpaRepository { +public interface GenreRepository extends JpaRepository, GenreRepositoryCustom { - boolean existsByName(String name); - - Optional findByIdAndDeletedAtIsNull(Long genreId); + @Query("select distinct g from Genre g left join fetch g.animeGenres where g.id = :id and g.deletedAt = null") + Optional findByIdAndDeletedAtIsNull(@Param("id") Long genreId); List findAllByDeletedAtIsNull(); } diff --git a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java new file mode 100644 index 00000000..4c76e509 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java @@ -0,0 +1,5 @@ +package io.oduck.api.domain.genre.repository; + +public interface GenreRepositoryCustom { + boolean existsByName(String name); +} diff --git a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java new file mode 100644 index 00000000..56c4ef08 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java @@ -0,0 +1,31 @@ +package io.oduck.api.domain.genre.repository; + +import static io.oduck.api.domain.genre.entity.QGenre.genre; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class GenreRepositoryCustomImpl implements GenreRepositoryCustom{ + + private final JPAQueryFactory queryFactory; + + @Override + public boolean existsByName(String name) { + Integer fetchOne = queryFactory + .selectOne() + .from(genre) + .where( + genre.name.eq(name), + notDeleted() + ).fetchFirst(); + return fetchOne != null; + } + + private BooleanExpression notDeleted() { + return genre.deletedAt.isNull(); + } +} diff --git a/src/main/java/io/oduck/api/domain/originalAuthor/entity/OriginalAuthor.java b/src/main/java/io/oduck/api/domain/originalAuthor/entity/OriginalAuthor.java index 5d6f75d2..b5691fc3 100644 --- a/src/main/java/io/oduck/api/domain/originalAuthor/entity/OriginalAuthor.java +++ b/src/main/java/io/oduck/api/domain/originalAuthor/entity/OriginalAuthor.java @@ -1,12 +1,18 @@ package io.oduck.api.domain.originalAuthor.entity; +import io.oduck.api.domain.anime.entity.Anime; +import io.oduck.api.domain.anime.entity.AnimeOriginalAuthor; import io.oduck.api.global.audit.BaseEntity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -22,14 +28,19 @@ public class OriginalAuthor extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, length = 50, unique = true) + @Column(nullable = false, length = 50) private String name; + @OneToMany(mappedBy = "originalAuthor", cascade = CascadeType.PERSIST, orphanRemoval = true) + @Builder.Default + private List animeOriginalAuthors = new ArrayList<>(); + public void update(String name) { this.name = name; } public void delete() { + this.animeOriginalAuthors.clear(); this.deletedAt = LocalDateTime.now(); } } diff --git a/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepository.java b/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepository.java index c0c420b6..2a7e3d99 100644 --- a/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepository.java +++ b/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepository.java @@ -1,16 +1,16 @@ package io.oduck.api.domain.originalAuthor.repository; -import com.querydsl.core.Fetchable; import io.oduck.api.domain.originalAuthor.entity.OriginalAuthor; import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -public interface OriginalAuthorRepository extends JpaRepository { +public interface OriginalAuthorRepository extends JpaRepository, OriginalAuthorRepositoryCustom { - boolean existsByName(String name); - - Optional findByIdAndDeletedAtIsNull(Long originalAuthorId); + @Query("select distinct oa from OriginalAuthor oa left join fetch oa.animeOriginalAuthors where oa.id = :id and oa.deletedAt = null") + Optional findByIdAndDeletedAtIsNull(@Param("id") Long originalAuthorId); List findAllByDeletedAtIsNull(); } diff --git a/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepositoryCustom.java b/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepositoryCustom.java new file mode 100644 index 00000000..a6119805 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepositoryCustom.java @@ -0,0 +1,5 @@ +package io.oduck.api.domain.originalAuthor.repository; + +public interface OriginalAuthorRepositoryCustom { + boolean existsByName(String name); +} diff --git a/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepositoryCustomImpl.java new file mode 100644 index 00000000..b1d1de3c --- /dev/null +++ b/src/main/java/io/oduck/api/domain/originalAuthor/repository/OriginalAuthorRepositoryCustomImpl.java @@ -0,0 +1,32 @@ +package io.oduck.api.domain.originalAuthor.repository; + + +import static io.oduck.api.domain.originalAuthor.entity.QOriginalAuthor.originalAuthor; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class OriginalAuthorRepositoryCustomImpl implements OriginalAuthorRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public boolean existsByName(String name) { + Integer fetchOne = queryFactory.selectOne() + .from(originalAuthor) + .where( + originalAuthor.name.eq(name), + notDeleted() + ) + .fetchFirst(); + return fetchOne != null; + } + + private BooleanExpression notDeleted() { + return originalAuthor.deletedAt.isNull(); + } +} diff --git a/src/main/java/io/oduck/api/domain/series/entity/Series.java b/src/main/java/io/oduck/api/domain/series/entity/Series.java index 17d0f02d..6297591f 100644 --- a/src/main/java/io/oduck/api/domain/series/entity/Series.java +++ b/src/main/java/io/oduck/api/domain/series/entity/Series.java @@ -1,12 +1,17 @@ package io.oduck.api.domain.series.entity; +import io.oduck.api.domain.anime.entity.Anime; import io.oduck.api.global.audit.BaseEntity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -22,14 +27,19 @@ public class Series extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, length = 50, unique = true) + @Column(nullable = false, length = 50) private String title; + @OneToMany(mappedBy = "series", cascade = CascadeType.PERSIST, orphanRemoval = true) + @Builder.Default + private List animes = new ArrayList<>(); + public void update(String title) { this.title = title; } public void delete() { + this.animes.clear(); this.deletedAt = LocalDateTime.now(); } } diff --git a/src/main/java/io/oduck/api/domain/series/repository/SeriesRepository.java b/src/main/java/io/oduck/api/domain/series/repository/SeriesRepository.java index f2f77a03..27d56477 100644 --- a/src/main/java/io/oduck/api/domain/series/repository/SeriesRepository.java +++ b/src/main/java/io/oduck/api/domain/series/repository/SeriesRepository.java @@ -4,12 +4,14 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.security.core.parameters.P; -public interface SeriesRepository extends JpaRepository { +public interface SeriesRepository extends JpaRepository, SeriesRepositoryCustom { - boolean existsByTitle(String title); - - Optional findByIdAndDeletedAtIsNull(Long seriesId); + @Query("select distinct s from Series s left join fetch s.animes where s.id = :id and s.deletedAt = null") + Optional findByIdAndDeletedAtIsNull(@Param("id") Long seriesId); List findAllByDeletedAtIsNull(); } diff --git a/src/main/java/io/oduck/api/domain/series/repository/SeriesRepositoryCustom.java b/src/main/java/io/oduck/api/domain/series/repository/SeriesRepositoryCustom.java new file mode 100644 index 00000000..2d2ce1fe --- /dev/null +++ b/src/main/java/io/oduck/api/domain/series/repository/SeriesRepositoryCustom.java @@ -0,0 +1,6 @@ +package io.oduck.api.domain.series.repository; + +public interface SeriesRepositoryCustom { + + boolean existsByTitle(String title); +} diff --git a/src/main/java/io/oduck/api/domain/series/repository/SeriesRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/series/repository/SeriesRepositoryCustomImpl.java new file mode 100644 index 00000000..e0cef3f5 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/series/repository/SeriesRepositoryCustomImpl.java @@ -0,0 +1,31 @@ +package io.oduck.api.domain.series.repository; + +import static io.oduck.api.domain.series.entity.QSeries.series; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class SeriesRepositoryCustomImpl implements SeriesRepositoryCustom{ + + private final JPAQueryFactory queryFactory; + + @Override + public boolean existsByTitle(String title) { + Integer fetchOne = queryFactory.selectOne() + .from(series) + .where( + series.title.eq(title), + notDeleted() + ) + .fetchFirst(); + return fetchOne != null; + } + + private BooleanExpression notDeleted() { + return series.deletedAt.isNull(); + } +} diff --git a/src/main/java/io/oduck/api/domain/studio/entity/Studio.java b/src/main/java/io/oduck/api/domain/studio/entity/Studio.java index d02d4f55..230c9b57 100644 --- a/src/main/java/io/oduck/api/domain/studio/entity/Studio.java +++ b/src/main/java/io/oduck/api/domain/studio/entity/Studio.java @@ -1,12 +1,17 @@ package io.oduck.api.domain.studio.entity; +import io.oduck.api.domain.anime.entity.AnimeStudio; import io.oduck.api.global.audit.BaseEntity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -22,14 +27,19 @@ public class Studio extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, length = 50, unique = true) + @Column(nullable = false, length = 50) private String name; + @OneToMany(mappedBy = "studio", cascade = CascadeType.PERSIST, orphanRemoval = true) + @Builder.Default + private List animeStudios = new ArrayList<>(); + public void update(String name) { this.name = name; } public void delete() { + this.animeStudios.clear(); this.deletedAt = LocalDateTime.now(); } } diff --git a/src/main/java/io/oduck/api/domain/studio/repository/StudioRepository.java b/src/main/java/io/oduck/api/domain/studio/repository/StudioRepository.java index 353ae1bd..399461a8 100644 --- a/src/main/java/io/oduck/api/domain/studio/repository/StudioRepository.java +++ b/src/main/java/io/oduck/api/domain/studio/repository/StudioRepository.java @@ -1,16 +1,16 @@ package io.oduck.api.domain.studio.repository; -import com.querydsl.core.Fetchable; import io.oduck.api.domain.studio.entity.Studio; import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -public interface StudioRepository extends JpaRepository { +public interface StudioRepository extends JpaRepository, StudioRepositoryCustom { - boolean existsByName(String name); - - Optional findByIdAndDeletedAtIsNull(Long studioId); + @Query("select distinct s from Studio s left join fetch s.animeStudios where s.id = :id and s.deletedAt = null") + Optional findByIdAndDeletedAtIsNull(@Param("id") Long studioId); List findAllByDeletedAtIsNull(); } diff --git a/src/main/java/io/oduck/api/domain/studio/repository/StudioRepositoryCustom.java b/src/main/java/io/oduck/api/domain/studio/repository/StudioRepositoryCustom.java new file mode 100644 index 00000000..a2b469d5 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/studio/repository/StudioRepositoryCustom.java @@ -0,0 +1,6 @@ +package io.oduck.api.domain.studio.repository; + +public interface StudioRepositoryCustom { + + boolean existsByName(String name); +} diff --git a/src/main/java/io/oduck/api/domain/studio/repository/StudioRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/studio/repository/StudioRepositoryCustomImpl.java new file mode 100644 index 00000000..d99e58da --- /dev/null +++ b/src/main/java/io/oduck/api/domain/studio/repository/StudioRepositoryCustomImpl.java @@ -0,0 +1,31 @@ +package io.oduck.api.domain.studio.repository; + +import static io.oduck.api.domain.studio.entity.QStudio.studio; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class StudioRepositoryCustomImpl implements StudioRepositoryCustom{ + + private final JPAQueryFactory queryFactory; + + @Override + public boolean existsByName(String name) { + Integer fetchOne = queryFactory.selectOne() + .from(studio) + .where( + studio.name.eq(name), + notDeleted() + ) + .fetchFirst(); + return fetchOne != null; + } + + private BooleanExpression notDeleted() { + return studio.deletedAt.isNull(); + } +} diff --git a/src/main/java/io/oduck/api/domain/voiceActor/entity/VoiceActor.java b/src/main/java/io/oduck/api/domain/voiceActor/entity/VoiceActor.java index 6f22cff1..ff557e6b 100644 --- a/src/main/java/io/oduck/api/domain/voiceActor/entity/VoiceActor.java +++ b/src/main/java/io/oduck/api/domain/voiceActor/entity/VoiceActor.java @@ -1,12 +1,17 @@ package io.oduck.api.domain.voiceActor.entity; +import io.oduck.api.domain.anime.entity.AnimeVoiceActor; import io.oduck.api.global.audit.BaseEntity; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -22,14 +27,19 @@ public class VoiceActor extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, length = 50, unique = true) + @Column(nullable = false, length = 50) private String name; + @OneToMany(mappedBy = "voiceActor", cascade = CascadeType.PERSIST, orphanRemoval = true) + @Builder.Default + private List animeVoiceActors = new ArrayList<>(); + public void update(String name) { this.name = name; } public void delete() { + animeVoiceActors.clear(); this.deletedAt = LocalDateTime.now(); } } \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepository.java b/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepository.java index 72da306b..d578e1b2 100644 --- a/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepository.java +++ b/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepository.java @@ -4,12 +4,13 @@ import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -public interface VoiceActorRepository extends JpaRepository { - - boolean existsByName(String name); +public interface VoiceActorRepository extends JpaRepository, VoiceActorRepositoryCustom { List findAllByDeletedAtIsNull(); - Optional findByIdAndDeletedAtIsNull(Long voiceActorId); + @Query("select distinct va from VoiceActor va left join fetch va.animeVoiceActors where va.id = :id and va.deletedAt = null") + Optional findByIdAndDeletedAtIsNull(@Param("id") Long voiceActorId); } diff --git a/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepositoryCustom.java b/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepositoryCustom.java new file mode 100644 index 00000000..dc2eb02c --- /dev/null +++ b/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepositoryCustom.java @@ -0,0 +1,6 @@ +package io.oduck.api.domain.voiceActor.repository; + +public interface VoiceActorRepositoryCustom { + + boolean existsByName(String name); +} diff --git a/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepositoryCustomImpl.java new file mode 100644 index 00000000..6bf87cf3 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/voiceActor/repository/VoiceActorRepositoryCustomImpl.java @@ -0,0 +1,31 @@ +package io.oduck.api.domain.voiceActor.repository; + +import static io.oduck.api.domain.voiceActor.entity.QVoiceActor.voiceActor; + +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class VoiceActorRepositoryCustomImpl implements VoiceActorRepositoryCustom { + + private final JPAQueryFactory queryFactory; + + @Override + public boolean existsByName(String name) { + Integer fetchOne = queryFactory.selectOne() + .from(voiceActor) + .where( + voiceActor.name.eq(name), + notDeleted() + ) + .fetchFirst(); + return fetchOne != null; + } + + private BooleanExpression notDeleted() { + return voiceActor.deletedAt.isNull(); + } +}