[내일배움캠프 Spring 4기 - 최종 프로젝트] 91일차 TIL : 이벤트-상품 중간 테이블 | QueryDSL 삭제 쿼리

서예진·2024년 4월 4일
0

오늘의 학습 키워드

이벤트-상품 중간 테이블
QueryDSL 삭제 쿼리
QueryDSL 3개 테이블 조인

📖 이벤트-상품 중간 테이블


요구사항

  • 하나의 이벤트에는 이벤트에 관련된 여러 상품을 같이 등록할 수 있다.
  • 여러 상품은 여러 이벤트에 속할 수 있다.
  • 여러 이벤트는 여러 상품을 가질 수 있다.

ERD

  • 위와 같은 요구사항으로 이벤트와 상품은 다대다 관계라고 생각되어 중간 테이블인 이벤트 상품 테이블을 만들었다.

Entity.java

EventProduct.java

@Getter
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class EventProduct {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "event_id")
	private Event event;

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "product_id")
	private Product product;

	public EventProduct(Event event, Product product) {
		this.event = event;
		this.product = product;
	}
}

DTO.java

EventProductRequest.java

@Getter
public class EventProductRequest {

	private Long productId;
}

EventRequest.java

  • 이벤트 상품 등록은 이벤트를 등록할 때, 같이 등록되게 request로 받아오게끔 했다.
  • request로 받아올 때 list로 받아온다.
@Getter
public class EventRequest {

	@NotNull(message = "이벤트를 등록하시려면 제목을 입력하세요.")
	private String title;

	@NotNull(message = "이벤트를 등록하시려면 내용을 입력하세요.")
	private String content;

	private Long limitNum;

	@NotNull(message = "이벤트를 등록하시려면 오픈일자를 입력하세요.")
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private LocalDate openAt;

	private List<EventProductRequest> eventProducts;

}

Service.java

EventServiceImpl.java

	@Transactional
	public Long createEvent(EventRequest eventRequest, User user) {

		Event event = new Event(eventRequest, user);
		Event savedEvent = eventRepository.save(event);

		eventRequest.getEventProducts().stream()
			.map(EventProductRequest::getProductId)
			.map(productId -> productRepository.findById(productId)
				.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 상품입니다.")))
			.map(product -> new EventProduct(savedEvent, product))
			.forEach(eventProductRepository::save);

		return savedEvent.getId();
	}
  • 이벤트를 등록할 때, list로 받아온 productId를 우선 존재하는 상품인지 검증하는 로직을 거친다. 검증하기 위해 ProductRepository를 주입받아와서 사용했다.
  • 이렇게 검증 로직을 거치면 product entity를 반환되고 이 product entity와 event entity를 통해 event product를 생성한다.
  • 객체가 생성되면 repository에 저장한다.
	@Transactional
	public void deleteEventProduct(Long eventProductId, User user) {

		EventProduct eventProduct = eventProductRepository.findById(eventProductId)
			.orElseThrow(() -> new IllegalArgumentException("해당 이벤트 상품은 존재하지 않습니다."));

		eventProductRepository.delete(eventProduct);
	}
  • 이벤트 상품을 수정하고 싶을 때는 이벤트 상품을 삭제함으로써 수정하게끔 했다.
  • @PathVariable 로 삭제하고싶은 이벤트 상품 ID를 받아오고 이 ID를 통해 실제 DB에 존재하는지 검증을 거친뒤 삭제한다.
	@Transactional
	public void deleteEvent(Long eventId, User user) {

		Event event = findEvent(eventId);

		if (!event.getUser().getId().equals(user.getId())) {
			throw new InvalidAdminEventException(INVALID_ADMIN_EVENT);
		}

		eventQuery.deleteEventProduct(eventId);
		eventRepository.delete(event);

	}
  • 이벤트를 삭제할 때, 관련된 이벤트 상품도 삭제되어야한다.
  • 이벤트 삭제될 때는 관련 기록이 필요할 것 같아 Soft Delete 방법을 채택한 반면, 이벤트 상품은 삭제된 객체를 굳이 DB에 가지고 있을 필요가 없다고 판단되어 Hard Delete 방법을 채택했다.
  • 이벤트 객체가 삭제되기 전에 관련된 이벤트 상품을 먼저 삭제하는 쿼리를 날린뒤 이벤트를 삭제하게끔 했다.

📖 QueryDSL 삭제 쿼리


  • 이벤트를 삭제할때, 관련된 이벤트 상품을 먼저 삭제하기 위해 QueryDSL을 이용하여 삭제 쿼리를 날렸다.
  • QueryDSL을 사용한 이유는 그동안 JPA를 통해서 삭제했기 때문에 한번 사용해보고자 QueryDSL을 사용했다.

EventQueryImpl.java

public void deleteEventProduct(Long eventId) {
		long count = jpaQueryFactory.delete(QEventProduct.eventProduct)
			.where(QEventProduct.eventProduct.event.id.eq(eventId))
			.execute();
	}
profile
안녕하세요

0개의 댓글