java.sql.SQLIntegrityConstraintViolationException Spring Boot 中的列“column_name”不能为空

问题描述 投票:0回答:1

我在 Spring Boot 示例中创建订单时遇到问题。当我向如下所示的 createOrder 发送 CreateOrderRequest 时,我遇到了这个问题。

{
  "orderDetailSet": [
    {
      "bookId": "bookId",
      "amount": 1
    }
  ]
}

这是下图所示的问题

java.sql.SQLIntegrityConstraintViolationException: Column 'order_id' cannot be null

我还修改了createOrder的相关部分,但没有任何改变。我仍然遇到同样的问题。

Order order = OrderMapper.toOrder(orderDTO);

// Associate each OrderItem with the Order
for (OrderItemDTO orderItemDTO : orderDetailDTOSet) {
    OrderItem orderItem = OrderItemMapper.toOrderItem(orderItemDTO);
    orderItem.setOrder(order);
}

// Save the Order, which should cascade to the associated OrderItems
Order orderCompleted = orderRepository.save(order);

return OrderMapper.toOrderDTO(orderCompleted);

这是如下所示的订单实体

@Entity
@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "ORDERS")
public class Order extends BaseEntity {

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

    @ManyToOne
    @JoinColumn(name = "userId", nullable = false)
    private User user;

    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<OrderItem> orderItems;

}

这是下面显示的 OrderItem

@Entity
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "ORDER_ITEMS")
public class OrderItem extends BaseEntity {

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

    @OneToOne
    @JoinColumn(name = "bookId")
    private Book book;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "orderId", referencedColumnName = "id", nullable = false)
    private Order order;
}

这里是OrderSaveServiceImpl的createOrder方法如下所示

@Transactional
@Override
public OrderDTO createOrder(CreateOrderRequest createOrderRequest) {

    CustomUserDetails customUserDetails = identity.getCustomUserDetails();

    User user = userService.findByEmail(customUserDetails.getEmail())
            .orElseThrow(() -> new UserNotFoundException(String.valueOf(customUserDetails.getId())));

    UserDTO userDTO = UserMapper.toDTO(user);

    Set<OrderItemDTO> orderDetailDTOSet = createOrderRequest
            .getOrderDetailSet()
            .stream()
            .map(orderItemService::createOrderItem)
            .collect(Collectors.toSet());


    OrderDTO orderDTO = OrderDTO.builder()
            .user(userDTO)
            .orderItems(orderDetailDTOSet)
            .createdAt(LocalDateTime.now())
            .build();

    Order order = OrderMapper.toOrder(orderDTO);

    Order orderCompleted = orderRepository.save(order);

    for (OrderItemDTO orderItemDTO : orderDetailDTOSet) {
        OrderItem orderItem = OrderItemMapper.toOrderItem(orderItemDTO);
        orderItem.setOrder(orderCompleted);
        orderItemRepository.save(orderItem);
    }

    return OrderMapper.toOrderDTO(orderCompleted);
}

这里是OrderItemServiceImpl的createOrderItem方法,如下所示

@Retryable(retryFor = StockModifiedException.class, maxAttempts = 2, backoff = @Backoff(delay = 100))
    @Override
    public OrderItemDTO createOrderItem(OrderItemRequest orderDetailRequest) {

        BookDTO bookDTO = bookService.getBookById(orderDetailRequest.getBookId());

        boolean stockAvailable = bookService.isStockAvailable(bookDTO, orderDetailRequest.getAmount());

        if (stockAvailable) {

            OrderItemDTO.OrderItemBook orderItemBook = OrderItemDTO.OrderItemBook.builder()
                    .isbn(bookDTO.getIsbn())
                    .price(bookDTO.getPrice().multiply(BigDecimal.valueOf(orderDetailRequest.getAmount())))
                    .authorFullName(bookDTO.getAuthorFullName())
                    .id(bookDTO.getId())
                    .version(bookDTO.getVersion())
                    .build();

            BookUpdateStockRequest bookUpdateStockRequest = BookUpdateStockRequest.builder()
                    .stock(bookDTO.getStock() - orderDetailRequest.getAmount())
                    .build();

            bookService.updateBookStockById(bookDTO.getId(), bookUpdateStockRequest);

            return OrderItemDTO.builder()
                    .book(orderItemBook)
                    .build();
        }

        throw new StockModifiedException();
    }

我该如何修复它?

这是回购协议:链接

java spring-boot collections dto
1个回答
0
投票

认为这是因为当你保存一个

Order
时,它也会级联保存它的
OrderItem
,因为
CascadeType.ALL
中的
@OneToMany

但是当时的

OrderItem
还没有配置它的
order
字段,所以它是 NULL,所以它的映射列
order_id
也抛出
SQLIntegrityConstraintViolationException

因此,请确保在保存 Order 时,其所有订单项都配置了

order
字段,使其与此 Order 实例相同。您可以通过在
Order
中创建辅助函数来添加
OrderItem
:

来简化它
@Entity
@Table(name = "ORDERS")
public class Order extends BaseEntity {


    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<OrderItem> orderItems;


    public void add(OrderItem item){
       this.orderItems.add(item);
       item.setOrder(this);
    }

}

也因为

CascadeType.ALL
,你不需要单独调用保存订单项。只需准备一个订单并正确配置其所有项目的状态,然后仅保存订单。

还有一条评论仅供参考,

FetchType.EAGER
对我来说是一种代码味道。强烈建议您将其更改为延迟加载。

© www.soinside.com 2019 - 2024. All rights reserved.