PK가 BIGINT, Auto_Increment이고 다른 한 속성에 Unique 제약을 걸어 들어오는 데이터를 저장하던 중 문제가 발생했다.
id값이 1, 2, 3에서 잘 들어가다 같은 값이 들어가는지 아닌지 확인을 위해 id가 1, 2, 3과 같은 데이터를 넣는 요청 이후 신규 데이터를 넣으면 pk인 id가 연속되지 않고 15, 16, 17로 뛰어버리는 문제이다.
테이블을 앞서 얘기한 방식으로 작성한 이유는 구현해야하는 것의 제약사항을 따르다 보니 자연스럽게 나온 것이다.
흠... 그렇다면 그 제약사항이란... 요청 데이터 한 식당의 메뉴 이름과 가격이 넘어오는데 (검증 처리는 논외) 이름이 DB테이블에 이미 존재하는 하는 것이라면 등록을 하면 안된다는 것이다.
생각한 구현 방법들은 아래와 같다.
a. JPA를 최대한 활용하여 구현 하는 방법 (너무 막연하다...)
b. Entity의 @Id를 name으로 하고 중복된 값이 넘어오지 않게 하는 방법
c. JPA의 힘을 좀 빼고, Schema.sql을 만들어 DB테이블을 논리적으로 설계하는 방법
d. 우선 DB를 조회한 음식의 이름과 등록하려는 이름을 비교 후 동일한 이름이 없다면 등록하는 방법
이 네 가지 중에 무엇이 좋은 방법인지 모르겠지만 가장 최적의 방법을 찾고 만나는 문제를 해결해야 할 것 같다.
Entity의 구현 사항
name 필드의 unique 제약 사항은 제거해야 하는 것인지 아직 모르겠다
public class Food extends Timestamped {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "restaurant_id", nullable = false)
private Long restaurantId;
@Column(nullable = false, unique = true)
private String name;
@Column(nullable = false)
private String price;
@Builder
public Food(Long restaurantId, String name, String price) {
this.restaurantId = restaurantId;
this.name = name;
this.price = price;
}
}
Repository의 구현 사항
public interface FoodRepository extends JpaRepository<Food, Long> {
boolean existsByName(String name);
}
Service의 구현 사항
public class FoodService {
private final FoodRepository foodRepository;
@Transactional
public void saveFoods(SaveFoodRequestDto requestDto, Long restaurantId) throws Exception {
List<SaveFoodDto> foodList = requestDto.getFoods();
for (SaveFoodDto food : foodList) {
if (isFoodNameExist(food.getName())) {
throw new FoodNameExistException("name:'" + food.getName() + "'은/는 이미 존재하는 음식명입니다");
}
}
foodRepository.saveAll(requestDto.toEntities(restaurantId));
}
private boolean isFoodNameExist(String foodName) {
return foodRepository.existsByName(foodName);
}
}
전체 로직은 우선 특정 음식점의 사용자로부터 음식의 이름과 가격 정보 데이터가 들어온다.
해당 음식점에 같은 음식명이 하나라도 존재하는지 foodRepository의 existsByName을 통해 확인한 후에 존재하는 경우에는 'FoodNameExistException'을 발생시켜 모든 요청 데이터를 등록하지 않는 것이다.
우선은 이러한 로직으로 데이터를 등록하도록 구현을 했다.
더 좋은 방법이 있으면 언제든지 그 방법을 시도하고 적용할 계획이다!