最好用一个例子来提问,这样......
实体 PurchaseOrder
有一个列表 PurchaseOrderDetail
。 OneToMany
关系。 Entity
和list items
无法直接保存使用的 JPA 方法,因为涉及一些计算。
当我们对 PurchaseOrder
执行更新时我们必须保留主键,以便我们可以像这样更新
PurchaseOrder purchaseOrder = purchaseOrderRepository.getOne(purchaseOrderRequest.getId());
purchaseOrder.setSupplier(purchaseOrderRequest.getSupplier());
purchaseOrder.setDollarRate(purchaseOrderRequest.getDollarRate());
purchaseOrder.setShippingCost(purchaseOrderRequest.getShippingCost());
return purchaseOrderRepository.save(purchaseOrder);
但是如何Beautifully
更新List<PurchaseOrderDetail> purchaseOrderDetails
?
我有以下代码,它将删除现有列表项并插入丢失主键的新项目。但是 JPA way
是什么?这样做,以便在更新期间发生以下情况
1. If some items were deleted they should be deleted from DB.
2. If some items were updated they should be updated preserving the primary keys.
3. If some new items are added they should be created having new primary keys.
代码
purchaseOrder.setPurchaseOrderDetails(null);
for (PurchaseOrderDetailRequest purchaseOrderDetailRequest : purchaseOrderRequest.getPurchaseOrderDetails())
{
PurchaseOrderDetail purchaseOrderDetail = new PurchaseOrderDetail();
purchaseOrderDetail.setPartNumber(purchaseOrderDetailRequest.getPartNumber());
purchaseOrderDetail.setDescription(purchaseOrderDetailRequest.getDescription());
purchaseOrderDetail.setQuantity(purchaseOrderDetailRequest.getQuantity());
purchaseOrderDetail.setUnitPriceInDollars(purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setTotalPriceInDollars(purchaseOrderDetailRequest.getQuantity() * purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setUnitPriceInSAR(purchaseOrder.getDollarRate() * purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setTotalPriceInSAR(purchaseOrderDetailRequest.getQuantity() * purchaseOrderDetail.getUnitPriceInSAR());
purchaseOrderDetail.setUnitCost(purchaseOrderDetail.getUnitPriceInSAR() + shippingFactor);
purchaseOrder.addPurchaseOrderDetail(purchaseOrderDetail);
}
采购订单
@Entity
@Table(name = "purchaseOrders")
public class PurchaseOrder extends UserDateAudit
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 140)
private String supplier;
@NotNull
private Float dollarRate;
@NotNull
private Float amount;
@NotNull
private Float shippingCost;
@OneToMany(
mappedBy = "purchaseOrder",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
@Fetch(FetchMode.SELECT)
@BatchSize(size = 150)
private List<PurchaseOrderDetail> purchaseOrderDetails = new ArrayList<>();
}
采购订单详细信息
@Entity
@Table(name = "purchaseOrderDetails")
public class PurchaseOrderDetail
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 50)
private String partNumber;
@Size(max = 256)
private String description;
@NotNull
private Integer quantity;
@NotNull
private Float unitPriceInDollars;
@NotNull
private Float totalPriceInDollars;
@NotNull
private Float unitPriceInSAR;
@NotNull
private Float totalPriceInSAR;
@NotNull
private Float unitCost;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "purchaseOrder_id", nullable = false)
private PurchaseOrder purchaseOrder;
}
最佳答案
JpaRepository.save()
根据实体状态执行 em.persist()
或 em.merge()
。
并且您还配置了 @OneToMany
关系与 cascade = CascadeType.ALL
和 orphanRemoval = true
的映射,因此您的方式是正确的.
您需要在代码中执行的操作是更新 PurchaseOrder
中定义的列表的 PurchaseOrderDetail
元素,而不是为它们创建新实例。
如果需要,您可以在映射中添加现有元素以加快查找处理速度。
// collect existing details into a map to fast up
Map<Long, PurchaseOrderDetail> purchaseOrderDetailByIdMap =
purchaseOrder.getPurchaseOrderDetails()
.stream()
.collect(toMap(PurchaseOrderDetail::getId, p -> p);
//collect new details into a list
List<PurchaseOrderDetail> updatedDetails =
purchaseOrderRequest.getPurchaseOrderDetails()
.stream()
.map(detailReq -> mapDetailRequestToDetail(detailReq,
purchaseOrderDetailByIdMap))
.collect(toList());
// overwrite the relationship with the updatedDetails var
purchaseOrder.setPurchaseOrderDetails(updatedDetails);
// ...
// mapping function extracted to be clearer
private PurchaseOrderDetail mapDetailRequestToDetail(PurchaseOrderDetailRequest purchaseOrderDetailRequest,
Map<Long, PurchaseOrderDetail> purchaseOrderDetailByIdMap) {
// Here you get the existing element with the defined id or you create a new one
PurchaseOrderDetail purchaseOrderDetail =
purchaseOrderDetailByIdMap.computeIfAbsent(purchaseOrderDetailRequest.getId(), k-> new PurchaseOrderDetail());
// set fields
purchaseOrderDetail.setPartNumber(purchaseOrderDetailRequest.getPartNumber());
purchaseOrderDetail.setDescription(purchaseOrderDetailRequest.getDescription());
purchaseOrderDetail.setQuantity(purchaseOrderDetailRequest.getQuantity());
purchaseOrderDetail.setUnitPriceInDollars(purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setTotalPriceInDollars(purchaseOrderDetailRequest.getQuantity() * purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setUnitPriceInSAR(purchaseOrder.getDollarRate() * purchaseOrderDetailRequest.getUnitPriceInDollars());
purchaseOrderDetail.setTotalPriceInSAR(purchaseOrderDetailRequest.getQuantity() * purchaseOrderDetail.getUnitPriceInSAR());
purchaseOrderDetail.setUnitCost(purchaseOrderDetail.getUnitPriceInSAR() + shippingFactor);
return purchaseOrderDetail;
}
关于java - 使用 JpaRepository 更新实体中的列表项(保留主键),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54386667/