如何通过Spring JPA实现采购订单关联多个组件?
实现单个采购订单关联多个Component的方案
要实现单个用户采购订单存储多个Component的需求,你需要调整实体间的关联关系。根据业务场景,推荐两种实现方式:
方式一:使用关联实体(推荐,支持额外业务字段)
实际业务中,采购订单里的组件通常需要记录购买数量等额外信息,这时需要创建一个中间关联实体(如PurchaseOrderItem)来维护PurchaseOrder和Component的多对多关系。
1. 创建关联实体 PurchaseOrderItem
@Entity @Table(name = "purchase_order_items") public class PurchaseOrderItem { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; // 每个组件的购买数量(业务必填字段) @Column(name = "quantity", nullable = false) private Integer quantity; @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "purchase_order_id", nullable = false, foreignKey = @ForeignKey(name = "FK_PO_ITEM_PO")) private PurchaseOrder purchaseOrder; @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "component_id", nullable = false, foreignKey = @ForeignKey(name = "FK_PO_ITEM_COMPONENT")) private Component component; // Getter、Setter、toString方法自行补充 }
2. 修改 PurchaseOrder 实体
移除原有的单个Component字段,替换为关联PurchaseOrderItem的集合:
@Entity @Table(name = "purchase_order") public class PurchaseOrder { @GeneratedValue(strategy = GenerationType.IDENTITY) @Id @Column(name = "id", nullable = false) private Integer id; @Enumerated(EnumType.STRING) // 明确枚举存储类型,避免默认ORDINAL的风险 @Column(name = "status") private PurchaseOrderStatus purchaseOrderStatus; @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "user_id", nullable = false, foreignKey = @ForeignKey(name = "FK_PO_USER")) private User user; // 关联订单条目集合,级联操作+孤儿移除确保数据一致性 @OneToMany(mappedBy = "purchaseOrder", cascade = CascadeType.ALL, orphanRemoval = true) private List<PurchaseOrderItem> orderItems = new ArrayList<>(); // 辅助方法:快速添加组件到订单 public void addComponent(Component component, int quantity) { PurchaseOrderItem item = new PurchaseOrderItem(); item.setComponent(component); item.setQuantity(quantity); item.setPurchaseOrder(this); orderItems.add(item); component.getOrderItems().add(item); // 维护反向关联 } // Getter、Setter、toString方法自行补充 }
3. 修改 Component 实体
更新关联字段为PurchaseOrderItem集合:
@Entity @Table(name = "components", schema = "public", catalog = "inventory_db") public class Component { @GeneratedValue(strategy = GenerationType.IDENTITY) @Id @Column(name = "id", nullable = false) private Integer id; @Column(name = "qty") private Integer qty; @OneToMany(mappedBy = "component", cascade = CascadeType.ALL, orphanRemoval = true) @ToString.Exclude private List<PurchaseOrderItem> orderItems = new ArrayList<>(); // Getter、Setter、toString方法自行补充 }
4. 使用示例
// 从数据库查询已存在的用户和组件 User user = userRepository.findById(1).orElseThrow(); Component component1 = componentRepository.findById(101).orElseThrow(); Component component2 = componentRepository.findById(102).orElseThrow(); // 创建订单并关联组件 PurchaseOrder order = new PurchaseOrder(); order.setPurchaseOrderStatus(PurchaseOrderStatus.CREATED); order.setUser(user); order.addComponent(component1, 5); order.addComponent(component2, 3); // 保存订单(级联保存所有关联的订单条目) purchaseOrderRepository.save(order);
方式二:直接使用@ManyToMany(无额外字段场景)
如果你的业务不需要记录组件的购买数量等额外信息,可以直接通过@ManyToMany注解配置多对多关系,自动生成中间关联表:
1. 修改 PurchaseOrder 实体
@Entity @Table(name = "purchase_order") public class PurchaseOrder { // 原有字段保持不变 @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable( name = "purchase_order_components", // 中间表名称 joinColumns = @JoinColumn(name = "purchase_order_id"), inverseJoinColumns = @JoinColumn(name = "component_id"), foreignKeys = { @ForeignKey(name = "FK_PO_COMPONENT_PO"), @ForeignKey(name = "FK_PO_COMPONENT_COMPONENT") } ) private List<Component> components = new ArrayList<>(); // Getter、Setter、toString方法自行补充 }
2. 修改 Component 实体
@Entity @Table(name = "components", schema = "public", catalog = "inventory_db") public class Component { // 原有字段保持不变 @ManyToMany(mappedBy = "components") @ToString.Exclude private List<PurchaseOrder> purchaseOrders = new ArrayList<>(); // Getter、Setter、toString方法自行补充 }
内容的提问来源于stack exchange,提问作者Andrei Gavrilov
相关产品推荐
相关产品推荐

