diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsRequest.java b/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsRequest.java index da7f424424..de6fa52498 100644 --- a/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsRequest.java +++ b/src/main/java/in/koreatech/koin/domain/ownershop/dto/OwnerShopsRequest.java @@ -58,7 +58,7 @@ public Shop toEntity(Owner owner) { .phone(phone) .name(name) .internalName(name) - .chosung(name().substring(0, 1)) + .chosung(name.substring(0, 1)) .isDeleted(false) .isEvent(false) .remarks("") diff --git a/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java b/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java index 5c79d9010c..9415f6f53f 100644 --- a/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java +++ b/src/main/java/in/koreatech/koin/domain/ownershop/service/OwnerShopService.java @@ -42,17 +42,18 @@ public OwnerShopsResponse getOwnerShops(Long ownerId) { public void createOwnerShops(Long ownerId, OwnerShopsRequest ownerShopsRequest) { Owner owner = ownerRepository.getById(ownerId); Shop newShop = ownerShopsRequest.toEntity(owner); - shopRepository.save(newShop); + Shop savedShop = shopRepository.save(newShop); + for (String imageUrl : ownerShopsRequest.imageUrls()) { ShopImage shopImage = ShopImage.builder() - .shop(newShop) + .shop(savedShop) .imageUrl(imageUrl) .build(); shopImageRepository.save(shopImage); } for (OwnerShopsRequest.InnerOpenRequest open : ownerShopsRequest.open()) { ShopOpen shopOpen = ShopOpen.builder() - .shop(newShop) + .shop(savedShop) .openTime(open.openTime()) .closeTime(open.closeTime()) .dayOfWeek(open.dayOfWeek()) @@ -64,7 +65,7 @@ public void createOwnerShops(Long ownerId, OwnerShopsRequest ownerShopsRequest) for (ShopCategory shopCategory : shopCategories) { ShopCategoryMap shopCategoryMap = ShopCategoryMap.builder() .shopCategory(shopCategory) - .shop(newShop) + .shop(savedShop) .build(); shopCategoryMapRepository.save(shopCategoryMap); } diff --git a/src/main/java/in/koreatech/koin/domain/shop/dto/ShopResponse.java b/src/main/java/in/koreatech/koin/domain/shop/dto/ShopResponse.java index ab493228b3..8d7f1887e2 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/dto/ShopResponse.java +++ b/src/main/java/in/koreatech/koin/domain/shop/dto/ShopResponse.java @@ -10,6 +10,7 @@ import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; import in.koreatech.koin.domain.shop.model.MenuCategory; import in.koreatech.koin.domain.shop.model.Shop; +import in.koreatech.koin.domain.shop.model.ShopCategory; import in.koreatech.koin.domain.shop.model.ShopCategoryMap; import in.koreatech.koin.domain.shop.model.ShopImage; import in.koreatech.koin.domain.shop.model.ShopOpen; @@ -61,31 +62,7 @@ public record ShopResponse( LocalDateTime updatedAt ) { - public static ShopResponse of(Shop shop, List shopOpens, List shopImages, - List shopCategoryMaps, List menuCategories) { - - List innerShopOpens = shopOpens.stream().map(shopOpen -> new InnerShopOpen( - shopOpen.getDayOfWeek(), - shopOpen.getClosed(), - shopOpen.getOpenTime(), - shopOpen.getCloseTime() - )).toList(); - - List imageUrls = shopImages.stream().map(shopImage -> shopImage.getImageUrl()).toList(); - - List innerShopCategories = shopCategoryMaps.stream() - .map(shopCategoryMap -> new InnerShopCategory( - shopCategoryMap.getShopCategory().getId(), - shopCategoryMap.getShopCategory().getName() - )) - .toList(); - - List innerMenuCategories = menuCategories.stream() - .map(menuCategory -> new InnerMenuCategory( - menuCategory.getId(), - menuCategory.getName() - )) - .toList(); + public static ShopResponse from(Shop shop) { return new ShopResponse( shop.getAddress(), @@ -93,14 +70,34 @@ public static ShopResponse of(Shop shop, List shopOpens, List shopImage.getImageUrl()) + .toList(), + shop.getMenuCategories().stream().map(menuCategory -> { + return new InnerMenuCategory( + menuCategory.getId(), + menuCategory.getName() + ); + }).toList(), shop.getName(), - innerShopOpens, + shop.getShopOpens().stream().map(shopOpen -> { + return new InnerShopOpen( + shopOpen.getDayOfWeek(), + shopOpen.getClosed(), + shopOpen.getOpenTime(), + shopOpen.getCloseTime() + ); + }).toList(), shop.getPayBank(), shop.getPayCard(), shop.getPhone(), - innerShopCategories, + shop.getShopCategories().stream().map(shopCategoryMap -> { + ShopCategory shopCategory = shopCategoryMap.getShopCategory(); + return new InnerShopCategory( + shopCategory.getId(), + shopCategory.getName() + ); + }).toList(), shop.getUpdatedAt() ); } diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategory.java b/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategory.java index e37a93e242..f14232c3d9 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategory.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategory.java @@ -8,9 +8,12 @@ import in.koreatech.koin.global.domain.BaseEntity; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; @@ -31,8 +34,9 @@ public final class MenuCategory extends BaseEntity { private Long id; @NotNull - @Column(name = "shop_id", nullable = false) - private Long shopId; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "shop_id", nullable = false) + private Shop shop; @Size(max = 255) @NotNull @@ -47,8 +51,8 @@ public final class MenuCategory extends BaseEntity { private List menuCategoryMaps = new ArrayList<>(); @Builder - private MenuCategory(Long shopId, String name) { - this.shopId = shopId; + private MenuCategory(Shop shop, String name) { + this.shop = shop; this.name = name; } } diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java b/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java index 23cb16378f..f63f31828b 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/Shop.java @@ -1,7 +1,11 @@ package in.koreatech.koin.domain.shop.model; +import static jakarta.persistence.CascadeType.*; import static lombok.AccessLevel.PROTECTED; +import java.util.ArrayList; +import java.util.List; + import org.hibernate.annotations.Where; import in.koreatech.koin.domain.owner.model.Owner; @@ -15,6 +19,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.Lob; import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -96,10 +101,40 @@ public class Shop extends BaseEntity { @Column(name = "hit", nullable = false) private Long hit; + @OneToMany(mappedBy = "shop", orphanRemoval = true, cascade = {PERSIST, REMOVE}) + private List shopCategories = new ArrayList<>(); + + @OneToMany(mappedBy = "shop", orphanRemoval = true, cascade = {PERSIST, REMOVE}) + private List shopOpens = new ArrayList<>(); + + @OneToMany(mappedBy = "shop", orphanRemoval = true, cascade = {PERSIST, REMOVE}) + private List shopImages = new ArrayList<>(); + + @OneToMany(mappedBy = "shop", orphanRemoval = true, cascade = {PERSIST, REMOVE}) + private List menuCategories = new ArrayList<>(); + @Builder - private Shop(Owner owner, String name, String internalName, String chosung, String phone, String address, - String description, Boolean delivery, Long deliveryPrice, Boolean payCard, Boolean payBank, - Boolean isDeleted, Boolean isEvent, String remarks, Long hit) { + private Shop( + Owner owner, + String name, + String internalName, + String chosung, + String phone, + String address, + String description, + Boolean delivery, + Long deliveryPrice, + Boolean payCard, + Boolean payBank, + Boolean isDeleted, + Boolean isEvent, + String remarks, + Long hit, + List shopCategories, + List shopOpens, + List shopImages, + List menuCategories + ) { this.owner = owner; this.name = name; this.internalName = internalName; @@ -115,5 +150,9 @@ private Shop(Owner owner, String name, String internalName, String chosung, Stri this.isEvent = isEvent; this.remarks = remarks; this.hit = hit; + this.shopCategories = shopCategories; + this.shopOpens = shopOpens; + this.shopImages = shopImages; + this.menuCategories = menuCategories; } } diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/ShopCategory.java b/src/main/java/in/koreatech/koin/domain/shop/model/ShopCategory.java index 93040906b4..1269a8a9e3 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/ShopCategory.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/ShopCategory.java @@ -1,5 +1,11 @@ package in.koreatech.koin.domain.shop.model; +import static jakarta.persistence.CascadeType.PERSIST; +import static jakarta.persistence.CascadeType.REMOVE; + +import java.util.ArrayList; +import java.util.List; + import org.hibernate.annotations.Where; import in.koreatech.koin.global.domain.BaseEntity; @@ -8,6 +14,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; @@ -40,6 +47,9 @@ public class ShopCategory extends BaseEntity { @Column(name = "is_deleted", nullable = false) private Boolean isDeleted = false; + @OneToMany(mappedBy = "shopCategory", orphanRemoval = true, cascade = {PERSIST, REMOVE}) + private List shopCategoryMaps = new ArrayList<>(); + @Builder private ShopCategory(Long id, String name, String imageUrl, Boolean isDeleted) { this.id = id; diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/ShopOpen.java b/src/main/java/in/koreatech/koin/domain/shop/model/ShopOpen.java index fd34c8892f..2db199c511 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/ShopOpen.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/ShopOpen.java @@ -29,7 +29,6 @@ @Table(name = "shop_opens") @Where(clause = "is_deleted=0") public class ShopOpen extends BaseEntity { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", nullable = false) @@ -49,12 +48,12 @@ public class ShopOpen extends BaseEntity { @NotNull @Column(name = "open_time") - @Convert(converter = LocalTimeAttributeConverter.class) + @Convert(converter = LocalTimeAttributeConverter.class) private LocalTime openTime; @NotNull @Column(name = "close_time") - @Convert(converter = LocalTimeAttributeConverter.class) + @Convert(converter = LocalTimeAttributeConverter.class) private LocalTime closeTime; @NotNull diff --git a/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java b/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java index c19b60152f..adf16c5a67 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java +++ b/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java @@ -32,9 +32,6 @@ public class ShopService { private final MenuRepository menuRepository; private final MenuCategoryRepository menuCategoryRepository; private final ShopRepository shopRepository; - private final ShopOpenRepository shopOpenRepository; - private final ShopCategoryMapRepository shopCategoryMapRepository; - private final ShopImageRepository shopImageRepository; public MenuDetailResponse findMenu(Long menuId) { Menu menu = menuRepository.getById(menuId); @@ -62,11 +59,7 @@ public MenuCategoriesResponse getMenuCategories(Long shopId) { public ShopResponse getShop(Long shopId) { Shop shop = shopRepository.getById(shopId); - List shopOpens = shopOpenRepository.findAllByShopId(shopId); - List shopImages = shopImageRepository.findAllByShopId(shopId); - List shopCategoryMaps = shopCategoryMapRepository.findAllByShopId(shopId); - List menuCategories = menuCategoryRepository.findAllByShopId(shopId); - return ShopResponse.of(shop, shopOpens, shopImages, shopCategoryMaps, menuCategories); + return ShopResponse.from(shop); } public ShopMenuResponse getShopMenu(Long shopId) { diff --git a/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java index 5e4620255f..a975a81d10 100644 --- a/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/OwnerShopApiTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.transaction.annotation.Transactional; import in.koreatech.koin.AcceptanceTest; import in.koreatech.koin.domain.owner.model.Owner; @@ -189,19 +190,19 @@ void createOwnerShop() { "010-1234-5678" ); - ShopCategory shopCategoryRequest1 = ShopCategory.builder() + ShopCategory shopCategory1 = ShopCategory.builder() .isDeleted(false) .name("테스트1") .imageUrl("https://test.com/test1.jpg") .build(); - ShopCategory shopCategoryRequest2 = ShopCategory.builder() + ShopCategory shopCategory2 = ShopCategory.builder() .isDeleted(false) .name("테스트2") .imageUrl("https://test.com/test2.jpg") .build(); - shopCategoryRepository.save(shopCategoryRequest1); - shopCategoryRepository.save(shopCategoryRequest2); + shopCategoryRepository.save(shopCategory1); + shopCategoryRepository.save(shopCategory2); ExtractableResponse response = RestAssured .given() @@ -231,11 +232,11 @@ void createOwnerShop() { softly.assertThat(createdShop.getPayBank()).isEqualTo(ownerShopsRequest.payBank()); softly.assertThat(createdShop.getPayCard()).isEqualTo(ownerShopsRequest.payCard()); softly.assertThat(createdShop.getPhone()).isEqualTo(ownerShopsRequest.phone()); + softly.assertThat(shopOpens).hasSize(2); softly.assertThat(categoryIds).containsAnyElementsOf(shopCategoryMaps.stream() .map(shopCategory -> shopCategory.getShopCategory().getId()).toList()); softly.assertThat(imageUrls).containsAnyElementsOf(shopImages.stream() .map(ShopImage::getImageUrl).toList()); - softly.assertThat(shopOpens).hasSize(2); } ); } diff --git a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java index 6810d7fd2d..51597820ef 100644 --- a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java @@ -148,7 +148,7 @@ void findMenuSingleOption() { .build(); MenuCategory menuCategory = MenuCategory.builder() - .shopId(1L) + .shop(shop) .name("중식") .build(); menuCategoryRepository.save(menuCategory); @@ -222,7 +222,7 @@ void findMenuMultipleOption() { .build(); MenuCategory menuCategory = MenuCategory.builder() - .shopId(1L) + .shop(shop) .name("중식") .build(); @@ -292,12 +292,12 @@ void findShopMenuCategories() { .build(); MenuCategory menuCategory1 = MenuCategory.builder() - .shopId(SHOP_ID) + .shop(shop) .name("이벤트 메뉴") .build(); MenuCategory menuCategory2 = MenuCategory.builder() - .shopId(SHOP_ID) + .shop(shop) .name("메인 메뉴") .build(); @@ -455,7 +455,7 @@ void getShopMenus() { .build(); MenuCategory menuCategory1 = MenuCategory.builder() - .shopId(1L) + .shop(shop) .name("중식") .build(); @@ -495,7 +495,7 @@ void getShopMenus() { .build(); MenuCategory menuCategory2 = MenuCategory.builder() - .shopId(1L) + .shop(shop) .name("한식") .build(); @@ -540,7 +540,7 @@ void getShopMenus() { menuRepository.save(menu3); MenuCategory menuCategory3 = MenuCategory.builder() - .shopId(1L) + .shop(shop) .name("이벤트") .build();