기존
에서
이 구조로 한번 변화시켜 볼 것이다.
Service에서 자동으로 생성되는 SpringDataJPA를 직접 쓰면서,
Querydsl이 필요한, 복잡한 동적 쿼리가 필요한 것은 저렇게 우리가 구현해 놓은 리포지토리를 쓴다.
즉, 같은 테이블 이지만 리포지토리를 2종류 쓰는 것이다.
여튼,
스프링데이터JPA는 스프링데이터JPA상속받은 인터페이스를 만들어 놓으면, 자동으로 빈에 등록이 되고,
Querydsl쓰는 리포지토리는 만들어서,
그 두개를 서비스에서 적절히 사용하면 된다.
@Entity
//@Table(name="item")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="item_name", length = 10)
private String itemName;
private Integer price;
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
도메인 @Entity라고 해 놔서 이지 알아서 잘 인식하고
@Id로 이게 id다 라고도 해 놓고
public interface ItemRepositoryV2 extends JpaRepository<Item, Long> {
}
그냥 이렇게 해두면 된다..
간단한 CRUD는 알아서 생긴다. ItemRepositoryV2가 자동으로 구현체로 생성되어 빈에 등록까지 된다.
단순한 insert나 id를 통한 조회, update 등 말고 동적 쿼리 같이 복잡한 부분들은,
@Repository
public class ItemQueryRepositoryV2 {
private final JPAQueryFactory query;
public ItemQueryRepositoryV2(EntityManager em) {
this.query = new JPAQueryFactory(em);
}
public List<Item> findAll(ItemSearchCond cond){
return query.select(item)
.from(item)
.where(getBuilderFromCond(cond))
.fetch();
}
BooleanBuilder getBuilderFromCond(ItemSearchCond cond){
String itemName = cond.getItemName();
Integer maxPrice = cond.getMaxPrice();
BooleanBuilder builder = new BooleanBuilder();
if(StringUtils.hasText(itemName)){
builder.and(item.itemName.like("%" + itemName +"%"));
}
if(maxPrice != null){
builder.and(item.price.loe(maxPrice));
}
return builder;
}
}
이렇게 직접 정의를 한다.
보면 딱 동적쿼리 필요한 부분만 작성해 놨다.
클래스 이름도 ItemQueryRepository 이런 것 뿐만 아니라 다른 걸 로도,
예를 들어 더 구체적이게 ItemSearchRepository 이런 식으로 해도 좋다.
쿼리공장을 만들 때에는 DB에 대한 정보를 가지고 있는 EntityManager가 필요하다.
뭐 저런 식으로 쉽게, 쿼리를 생성해서 fetch()해서 가져오기 까지 한다.
이 부분 코드에 대한 것은
https://qwefdg3.tistory.com/648
여기 참조
@Service
@RequiredArgsConstructor
@Transactional
public class ItemServiceV2 implements ItemService{
private final ItemRepositoryV2 repository;
private final ItemQueryRepositoryV2 queryRepository;
@Override
public Item save(Item item) {
repository.save(item);
return item;
}
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
Item findedItem = repository.findById(itemId).orElseThrow();
findedItem.setItemName(updateParam.getItemName());
findedItem.setPrice(updateParam.getPrice());
findedItem.setQuantity(updateParam.getQuantity());
}
@Override
public Optional<Item> findById(Long id) {
return repository.findById(id);
}
@Override
public List<Item> findItems(ItemSearchCond itemSearch) {
return queryRepository.findAll(itemSearch);
}
}
서비스.
자동으로 생성되는 ItemRepositoryV2는 주입받을 거다.
ItemQueryRepositoryV2도 빈으로 만들어 주입시킬 것이다.
간단하다. findItems의 동적 쿼리 사용하는 부분 빼고
SpringDataJPA를 쓰는 save, update, findById는 다 우리가 따로 구현하지 않아도 SpringDataJPA에서 제공해 주는 것 들이다. 우리는 @Entity, 도메인에 대한 설정만 해주면 된다.
@Import(SpringDataJpaConfig.class)
@SpringBootApplication(scanBasePackages = "hello.itemservice.web")
public class ItemServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ItemServiceApplication.class, args);
}
}
@Import로 설정(Config)한거 넣고 실행.
SpringDataJPA + Querydsl의 조합이었다. 이상.
'스프링 > 6. 스프링 DB-2' 카테고리의 다른 글
40. 스프링 트랜잭션 테스트 (0) | 2023.10.14 |
---|---|
39. DB 접근 기술의 조합 (0) | 2023.10.14 |
37. 트레이드 오프, SpringDataJPA 사용에 따른 구조변화 (0) | 2023.10.13 |
36. Querydsl 적용 (0) | 2023.10.13 |
35. Querydsl 설정 (0) | 2023.10.13 |