zkvn99

[Java Spring] TransientPropertyValueException 본문

Trouble Shooting/Java

[Java Spring] TransientPropertyValueException

zkvn1103 2023. 10. 18. 21:39

 

Hibernate와 JPA를 사용하여 데이터베이스에 엔터티를 저장하려고 할 때 발생하는 예외

19:46:14.178 [http-nio-8888-exec-5] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : laundry.daeseda.entity.order.OrderEntity.address -> laundry.daeseda.entity.user.AddressEntity; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : laundry.daeseda.entity.order.OrderEntity.address -> laundry.daeseda.entity.user.AddressEntity] with root cause
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : laundry.daeseda.entity.order.OrderEntity.address -> laundry.daeseda.entity.user.AddressEntity

클라이언트 측에서 JSON으로 DTO 객체를 넘겨준 것을 그대로 Entity로 만들고 그걸 외래키로 설정해서 문제가 발생한 것 같다

@Entity
@Table(name = "orders")

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderEntity extends BaseTimeEntity {

    @Id
    @Column(name = "order_id")
    @GeneratedValue
    private Long orderId;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private UserEntity user;

    @ManyToOne
    @JoinColumn(name = "address_id")
    private AddressEntity address;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    @Column
    private List<ClothesCountEntity> clothesCounts;

    @Enumerated(EnumType.STRING)
    @Column
    private OrderStatus orderStatus;

    @Column
    private int totalPrice;

    @Column
    private String washingMethod;

    @Column
    private LocalDate pickupDate;

    @Column
    private LocalDate deliveryDate;

    @Column
    private String deliveryLocation;

}

 

곰곰히 생각해보니 OrderEntity에 address 속성이 영속화 되지 않은 주소 엔티티를 참조하고 있어서 발생한 것이다

주문을 할 때마다 DB에 쿼리문을 날리는 양이 많아질까봐 줄이고 줄이다가 이렇게 된것이다..

 

Transient 상태의 엔티티는 JPA 관점에서는 데이터베이스와 관련이 없으며, 영속성 컨텍스트에 존재하지 않는 것으로 취급된다

 

다양한 해결방법이 있겠지만, 이번 목표는 Entity 클래스에서 Setter를 사용하지 않는 것이기에 욕심을 버리고 DB 접근으로 해결했다

@Transactional
    public void requestOrder(OrderDto orderDto) {

        String currentUserEmail = SecurityUtil.getCurrentUsername().get();
        UserEntity currentUser = userRepository.findByUserEmail(currentUserEmail).orElse(null);

        if (currentUser != null) {
            AddressEntity address = addressRepository.findById(orderDto.getAddress().getAddressId())
                    .orElseThrow(() -> new EntityNotFoundException("주소를 찾을 수 없습니다. ID: " + orderDto.getAddress().getAddressId()));


            OrderEntity orderEntity = OrderEntity.builder()
                    .user(currentUser)
                    .address(address)
                    .deliveryLocation(orderDto.getDeliveryLocation())
                    .totalPrice(orderDto.getTotalPrice())
                    .orderStatus(OrderStatus.ORDER)
                    .washingMethod(orderDto.getWashingMethod())
                    .pickupDate(orderDto.getPickupDate())
                    .deliveryDate(orderDto.getDeliveryDate())
                    .build();
            orderEntity = orderRepository.save(orderEntity);


            List<ClothesCountDto> clothesCountDtoList = orderDto.getClothesCount();
            System.out.println(clothesCountDtoList != null);
            if (clothesCountDtoList != null) {
                for (ClothesCountDto clothesCountDto : clothesCountDtoList) {
                    ClothesEntity clothesEntity = clothesRepository.findById(clothesCountDto.getClothes().getClothesId())
                            .orElseThrow(() -> new EntityNotFoundException("의류를 찾을 수 없습니다. ID: " + clothesCountDto.getClothes().getClothesId()));

                    ClothesCountEntity clothesCount = ClothesCountEntity.builder()
                            .clothes(clothesEntity)
                            .count(clothesCountDto.getCount())
                            .order(orderEntity)
                            .build();
                    orderClothesRepository.save(clothesCount);
                }
            }
        }
    }

이전 소스가 없어서 아쉽지만 주문 부분에서 DTO로 받아온 값을 통해서 주소를 조회한 값을 주문 Entity에 넣어주었다

 

'Trouble Shooting > Java' 카테고리의 다른 글

[Java Spring] Test NullPointerException  (0) 2023.09.17