실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 강의를 들으면 주문서비스 테스트를 작성하고, 실행했는데 에러를 만났다. 반가워~👋
에러메세지
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.jpabook.jpashop.domain.Order.delivery -> com.jpabook.jpashop.domain.Delivery; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.jpabook.jpashop.domain.Order.delivery -> com.jpabook.jpashop.domain.Delivery
- object references an unsaved transient instance
- save the transient instance before flushing
이 두 문장이 가장 눈에 들어온다. 저장되지 않은 인스턴스를 참조하려했으니, 플러싱 하기전에 저장해라~ 이런 느낌인듯 하다.
OrderService
@Service
@Transactional(readOnly = true)
class OrderService(
private val orderRepository: OrderRepository,
private val memberRepository: MemberRepository,
private val itemRepository: ItemRepository
) {
/**
* 주문
*/
@Transactional
fun order(memberId: Long, itemId: Long, count: Int): Long? {
// 엔티티 조회
val member = memberRepository.findOneById(memberId)
val item = itemRepository.findOneById(itemId)
// 배송정보 생성
val delivery = Delivery(member!!.address!!, null, DeliveryStatus.READY) // TODO: !! 제거
// 주문 상품 생성
val orderItem =
OrderItem().createOrderItem(item!!, item.price, count) // TODO: simplify
// 주문 생성
val order = Order(LocalDateTime.now(), OrderStatus.ORDER).createOrder(member, delivery, orderItem)
// 주문 저장
orderRepository.save(order)
return order.id
}
...
}
Service클래스의 주문 함수를 보면 Delivery, OrderItem엔티티도 생성하지만, Order엔티티만 DB에 저장을 하고있다.
JPA에 의해 Order와 연관된 Delivery, OrderItem도 Order를 저장하면 같이 저장된다고 강의에서 들었지만, 뭔가 이 부분에서 걸린 듯 보인다.
Order
package com.jpabook.jpashop.domain
import java.time.LocalDateTime
import javax.persistence.*
@Entity
@Table(name = "orders")
class Order(orderDate: LocalDateTime, status: OrderStatus) {
@Id
@GeneratedValue
@Column(name = "order_id")
var id: Long? = null
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
var member: Member? = null
@OneToMany(mappedBy = "order")
var orderItems: MutableList<OrderItem> = ArrayList()
@OneToOne
@JoinColumn(name = "delivery_id")
var delivery: Delivery? = null
var orderDate: LocalDateTime = orderDate
@Enumerated(EnumType.STRING)
var status: OrderStatus = status // Order, Cancel
//== 메서드 ==//
...
}
Order엔티티 저장시 함께 저장되어야 하는 delivery, orderItem에 Cascade 옵션이 있어야하는데 없다...!! 😅
해결방법
delivery, orderItem에 Cascade 옵션을 달아주면 해결~😉
@Entity
@Table(name = "orders")
class Order(orderDate: LocalDateTime, status: OrderStatus) {
@Id
@GeneratedValue
@Column(name = "order_id")
var id: Long? = null
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
var member: Member? = null
@OneToMany(mappedBy = "order", cascade = [CascadeType.ALL])
var orderItems: MutableList<OrderItem> = ArrayList()
@OneToOne(cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
@JoinColumn(name = "delivery_id")
var delivery: Delivery? = null
var orderDate: LocalDateTime = orderDate
@Enumerated(EnumType.STRING)
var status: OrderStatus = status // Order, Cancel
//== 메서드 ==//
...
}
전체코드