我正在构建一个电子商务 API,但现在我面临一个问题,我无法保存我的订单必须包含的产品列表。
我不知道我在实体之间使用的关系还是其他东西,但它们是:
订购
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne
@JoinColumn(name = "client_id", referencedColumnName = "cpf")
private Client client;
@OneToMany(mappedBy = "order")
private List<OrderProduct> products = new ArrayList<>();
@Column(name = "total")
private double total;
@Column(name = "status")
private StatusEnum status;
@Column(name = "createdAt")
private LocalDate createdAt;
public Order() {}
}
订购产品
@Entity
@Table(name = "order_products")
public class OrderProduct implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id")
private Product product;
@Column(name = "quantity")
private int quantity;
public OrderProduct(Order order, Product product, Integer quantity) {
this.order = order;
this.product = product;
this.quantity = quantity;
}
public double getTotalPrice() {
return this.product.getPrice() * this.quantity;
}
}
这是创建订单的服务方法
public Order create(OrderDTO orderObj) {
Client orderClient = clientService.get(orderObj.getClient());
Order order = new Order();
order.setCreatedAt(LocalDate.now());
order.setProducts(this.getOrderProducts(order, orderObj.getProducts()));
order.setClient(orderClient);
order.setTotal(this.getOrderTotal(order));
order.setStatus(StatusEnum.PROCESSING);
return orderRepository.save(order);
}
private List<OrderProduct> getOrderProducts(Order order, Map<Long, Integer> productsObj) {
List<OrderProduct> products = new ArrayList<>();
for (Map.Entry<Long, Integer> entry : productsObj.entrySet()) {
Product product = productService.updateProductStock(entry.getKey(), entry.getValue(), true);
products.add(new OrderProduct(order, product, entry.getValue()));
}
return products;
}
看来您在建立实体之间的关系方面走在正确的轨道上。然而,需要理解的一件重要的事情是,在双向关系中,您需要考虑双方。
保存
Order
时,不会自动保存与其关联的 OrderProduct
。这和JPA中的CascadeType
有关。如果你想同时保存 Order
和 OrderProducts
,你应该这样做:
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderProduct> products = new ArrayList<>();
这里,
CascadeType.ALL
表示在Order
上执行的所有操作(持久、合并、刷新、删除和分离)也将在OrderProduct
上执行。
但是,在这种情况下,简单添加级联类型可能还不够。问题的出现是由于 Hibernate 如何管理实体状态。当一个新的
OrderProduct
添加到 Order
时,Hibernate 并不知道它,因为当您向其添加新的 Order
时,OrderProducts
处于分离状态(在 getOrderProducts()
方法中)。
为了解决这个问题,我们需要确保关系的双方都正确更新。这通常涉及以下步骤:
OrderProduct
实体中,在构造函数的末尾添加 order.addProduct(this);
。在
Order
实体中:
public void addProduct(OrderProduct product){
products.add(product);
product.setOrder(this);
}
通过这种方式,可以双向管理关系,Hibernate 将了解该关系并继续对
cascade
设置采取行动。